You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@ignite.apache.org by ak...@apache.org on 2016/09/09 03:26:29 UTC

[01/52] ignite git commit: Web Console beta-3.

Repository: ignite
Updated Branches:
  refs/heads/master 31b9bb84d -> 39ec7d06b


http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/web-agent/src/main/java/org/apache/ignite/console/agent/handlers/RestHandler.java
----------------------------------------------------------------------
diff --git a/modules/web-console/web-agent/src/main/java/org/apache/ignite/console/agent/handlers/RestHandler.java b/modules/web-console/web-agent/src/main/java/org/apache/ignite/console/agent/handlers/RestHandler.java
new file mode 100644
index 0000000..1b4b565
--- /dev/null
+++ b/modules/web-console/web-agent/src/main/java/org/apache/ignite/console/agent/handlers/RestHandler.java
@@ -0,0 +1,276 @@
+/*
+ * 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.
+ */
+
+package org.apache.ignite.console.agent.handlers;
+
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.net.ConnectException;
+import java.net.URISyntaxException;
+import java.nio.charset.Charset;
+import java.util.List;
+import java.util.Map;
+import org.apache.commons.codec.Charsets;
+import org.apache.http.Header;
+import org.apache.http.NameValuePair;
+import org.apache.http.client.entity.UrlEncodedFormEntity;
+import org.apache.http.client.methods.CloseableHttpResponse;
+import org.apache.http.client.methods.HttpGet;
+import org.apache.http.client.methods.HttpPost;
+import org.apache.http.client.methods.HttpRequestBase;
+import org.apache.http.client.utils.URIBuilder;
+import org.apache.http.entity.StringEntity;
+import org.apache.http.impl.client.CloseableHttpClient;
+import org.apache.http.impl.client.HttpClientBuilder;
+import org.apache.ignite.console.agent.AgentConfiguration;
+import org.apache.ignite.console.demo.AgentClusterDemo;
+import org.apache.log4j.Logger;
+
+import static org.apache.ignite.console.agent.AgentConfiguration.DFLT_NODE_PORT;
+
+/**
+ * API to translate REST requests to Ignite cluster.
+ */
+public class RestHandler extends AbstractHandler {
+    /** */
+    private static final Logger log = Logger.getLogger(RestHandler.class.getName());
+
+    /** */
+    private final AgentConfiguration cfg;
+
+    /** */
+    private CloseableHttpClient httpClient;
+
+    /**
+     * @param cfg Config.
+     */
+    public RestHandler(AgentConfiguration cfg) {
+        this.cfg = cfg;
+    }
+
+    /**
+     * Start HTTP client for communication with node via REST.
+     */
+    public void start() {
+        httpClient = HttpClientBuilder.create().build();
+    }
+
+    /**
+     * Stop HTTP client.
+     */
+    public void stop() {
+        if (httpClient != null) {
+            try {
+                httpClient.close();
+            }
+            catch (IOException ignore) {
+                // No-op.
+            }
+        }
+    }
+
+    /** {@inheritDoc} */
+    @SuppressWarnings("unchecked")
+    @Override public Object execute(Map<String, Object> args) throws Exception {
+        if (log.isDebugEnabled())
+            log.debug("Start parse REST command args: " + args);
+
+        String uri = null;
+
+        if (args.containsKey("uri"))
+            uri = args.get("uri").toString();
+
+        Map<String, Object> params = null;
+
+        if (args.containsKey("params"))
+            params = (Map<String, Object>)args.get("params");
+
+        if (!args.containsKey("demo"))
+            throw new IllegalArgumentException("Missing demo flag in arguments: " + args);
+
+        boolean demo = (boolean)args.get("demo");
+
+        if (!args.containsKey("method"))
+            throw new IllegalArgumentException("Missing method in arguments: " + args);
+
+        String mtd = args.get("method").toString();
+
+        Map<String, Object> headers = null;
+
+        if (args.containsKey("headers"))
+            headers = (Map<String, Object>)args.get("headers");
+
+        String body = null;
+
+        if (args.containsKey("body"))
+            body = args.get("body").toString();
+
+        return executeRest(uri, params, demo, mtd, headers, body);
+    }
+
+    /**
+     * @param uri Url.
+     * @param params Params.
+     * @param demo Use demo node.
+     * @param mtd Method.
+     * @param headers Headers.
+     * @param body Body.
+     */
+    protected RestResult executeRest(String uri, Map<String, Object> params, boolean demo,
+        String mtd, Map<String, Object> headers, String body) throws IOException, URISyntaxException {
+        if (log.isDebugEnabled())
+            log.debug("Start execute REST command [method=" + mtd + ", uri=/" + (uri == null ? "" : uri) +
+                ", parameters=" + params + "]");
+
+        final URIBuilder builder;
+
+        if (demo) {
+            // try start demo if needed.
+            AgentClusterDemo.testDrive(cfg);
+
+            // null if demo node not started yet.
+            if (cfg.demoNodeUri() == null)
+                return RestResult.fail("Demo node is not started yet.", 404);
+
+            builder = new URIBuilder(cfg.demoNodeUri());
+        }
+        else
+            builder = new URIBuilder(cfg.nodeUri());
+
+        if (builder.getPort() == -1)
+            builder.setPort(DFLT_NODE_PORT);
+
+        if (uri != null) {
+            if (!uri.startsWith("/") && !cfg.nodeUri().endsWith("/"))
+                uri = '/' + uri;
+
+            builder.setPath(uri);
+        }
+
+        if (params != null) {
+            for (Map.Entry<String, Object> entry : params.entrySet()) {
+                if (entry.getValue() != null)
+                    builder.addParameter(entry.getKey(), entry.getValue().toString());
+            }
+        }
+
+        HttpRequestBase httpReq = null;
+
+        try {
+            if ("GET".equalsIgnoreCase(mtd))
+                httpReq = new HttpGet(builder.build());
+            else if ("POST".equalsIgnoreCase(mtd)) {
+                HttpPost post;
+
+                if (body == null) {
+                    List<NameValuePair> nvps = builder.getQueryParams();
+
+                    builder.clearParameters();
+
+                    post = new HttpPost(builder.build());
+
+                    if (!nvps.isEmpty())
+                        post.setEntity(new UrlEncodedFormEntity(nvps));
+                }
+                else {
+                    post = new HttpPost(builder.build());
+
+                    post.setEntity(new StringEntity(body));
+                }
+
+                httpReq = post;
+            }
+            else
+                throw new IOException("Unknown HTTP-method: " + mtd);
+
+            if (headers != null) {
+                for (Map.Entry<String, Object> entry : headers.entrySet())
+                    httpReq.addHeader(entry.getKey(), entry.getValue() == null ? null : entry.getValue().toString());
+            }
+
+            try (CloseableHttpResponse resp = httpClient.execute(httpReq)) {
+                ByteArrayOutputStream out = new ByteArrayOutputStream();
+
+                resp.getEntity().writeTo(out);
+
+                Charset charset = Charsets.UTF_8;
+
+                Header encodingHdr = resp.getEntity().getContentEncoding();
+
+                if (encodingHdr != null) {
+                    String encoding = encodingHdr.getValue();
+
+                    charset = Charsets.toCharset(encoding);
+                }
+
+                return RestResult.success(resp.getStatusLine().getStatusCode(), new String(out.toByteArray(), charset));
+            }
+            catch (ConnectException e) {
+                log.info("Failed connect to node and execute REST command [uri=" + builder.build() + "]");
+
+                return RestResult.fail("Failed connect to node and execute REST command.", 404);
+            }
+        }
+        finally {
+            if (httpReq != null)
+                httpReq.reset();
+        }
+    }
+
+    /**
+     * Request result.
+     */
+    public static class RestResult {
+        /** The field contains description of error if server could not handle the request. */
+        public final String error;
+
+        /** REST http code. */
+        public final int code;
+
+        /** The field contains result of command. */
+        public final String data;
+
+        /**
+         * @param error The field contains description of error if server could not handle the request.
+         * @param resCode REST http code.
+         * @param res The field contains result of command.
+         */
+        private RestResult(String error, int resCode, String res) {
+            this.error = error;
+            this.code = resCode;
+            this.data = res;
+        }
+
+        /**
+         * @param error The field contains description of error if server could not handle the request.
+         * @param restCode REST http code.
+         * @return Request result.
+         */
+        public static RestResult fail(String error, int restCode) {
+            return new RestResult(error, restCode, null);
+        }
+
+        /**
+         * @param code REST http code.
+         * @param data The field contains result of command.
+         * @return Request result.
+         */
+        public static RestResult success(int code, String data) {
+            return new RestResult(null, code, data);
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/web-agent/src/main/java/org/apache/ignite/console/demo/AgentClusterDemo.java
----------------------------------------------------------------------
diff --git a/modules/web-console/web-agent/src/main/java/org/apache/ignite/console/demo/AgentClusterDemo.java b/modules/web-console/web-agent/src/main/java/org/apache/ignite/console/demo/AgentClusterDemo.java
new file mode 100644
index 0000000..09189b5
--- /dev/null
+++ b/modules/web-console/web-agent/src/main/java/org/apache/ignite/console/demo/AgentClusterDemo.java
@@ -0,0 +1,641 @@
+/*
+ * 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.
+ */
+
+package org.apache.ignite.console.demo;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.LinkedHashMap;
+import java.util.Random;
+import java.util.Set;
+import java.util.concurrent.Executors;
+import java.util.concurrent.ScheduledExecutorService;
+import java.util.concurrent.ScheduledThreadPoolExecutor;
+import java.util.concurrent.ThreadFactory;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.atomic.AtomicBoolean;
+import java.util.concurrent.atomic.AtomicInteger;
+import org.apache.ignite.Ignite;
+import org.apache.ignite.IgniteCache;
+import org.apache.ignite.Ignition;
+import org.apache.ignite.cache.CacheAtomicityMode;
+import org.apache.ignite.cache.QueryEntity;
+import org.apache.ignite.cache.QueryIndex;
+import org.apache.ignite.cache.QueryIndexType;
+import org.apache.ignite.cache.affinity.rendezvous.RendezvousAffinityFunction;
+import org.apache.ignite.configuration.CacheConfiguration;
+import org.apache.ignite.configuration.IgniteConfiguration;
+import org.apache.ignite.console.agent.AgentConfiguration;
+import org.apache.ignite.console.demo.model.Car;
+import org.apache.ignite.console.demo.model.Country;
+import org.apache.ignite.console.demo.model.Department;
+import org.apache.ignite.console.demo.model.Employee;
+import org.apache.ignite.console.demo.model.Parking;
+import org.apache.ignite.internal.IgniteEx;
+import org.apache.ignite.internal.util.typedef.F;
+import org.apache.ignite.logger.log4j.Log4JLogger;
+import org.apache.ignite.spi.communication.tcp.TcpCommunicationSpi;
+import org.apache.ignite.spi.discovery.tcp.TcpDiscoverySpi;
+import org.apache.ignite.spi.discovery.tcp.ipfinder.vm.TcpDiscoveryVmIpFinder;
+import org.apache.ignite.spi.swapspace.file.FileSwapSpaceSpi;
+import org.apache.ignite.transactions.Transaction;
+import org.apache.log4j.Logger;
+
+import static org.apache.ignite.IgniteSystemProperties.IGNITE_ATOMIC_CACHE_DELETE_HISTORY_SIZE;
+import static org.apache.ignite.IgniteSystemProperties.IGNITE_PERFORMANCE_SUGGESTIONS_DISABLED;
+import static org.apache.ignite.IgniteSystemProperties.IGNITE_UPDATE_NOTIFIER;
+import static org.apache.ignite.IgniteSystemProperties.IGNITE_JETTY_PORT;
+import static org.apache.ignite.IgniteSystemProperties.IGNITE_NO_ASCII;
+import static org.apache.ignite.events.EventType.EVTS_DISCOVERY;
+import static org.apache.ignite.internal.IgniteNodeAttributes.ATTR_REST_JETTY_ADDRS;
+import static org.apache.ignite.internal.IgniteNodeAttributes.ATTR_REST_JETTY_PORT;
+import static org.apache.ignite.transactions.TransactionConcurrency.PESSIMISTIC;
+import static org.apache.ignite.transactions.TransactionIsolation.REPEATABLE_READ;
+
+/**
+ * Demo for cluster features like SQL and Monitoring.
+ *
+ * Cache will be created and populated with data to query.
+ */
+public class AgentClusterDemo {
+    /** */
+    private static final Logger log = Logger.getLogger(AgentClusterDemo.class.getName());
+
+    /** */
+    private static final AtomicBoolean initLatch = new AtomicBoolean();
+
+    /** */
+    private static final int NODE_CNT = 3;
+
+    /** */
+    private static final String COUNTRY_CACHE_NAME = "CountryCache";
+
+    /** */
+    private static final String DEPARTMENT_CACHE_NAME = "DepartmentCache";
+
+    /** */
+    private static final String EMPLOYEE_CACHE_NAME = "EmployeeCache";
+
+    /** */
+    private static final String PARKING_CACHE_NAME = "ParkingCache";
+
+    /** */
+    private static final String CAR_CACHE_NAME = "CarCache";
+
+    /** */
+    private static final Set<String> DEMO_CACHES = new HashSet<>(Arrays.asList(COUNTRY_CACHE_NAME,
+        DEPARTMENT_CACHE_NAME, EMPLOYEE_CACHE_NAME, PARKING_CACHE_NAME, CAR_CACHE_NAME));
+
+    /** */
+    private static final Random rnd = new Random();
+
+    /** Countries count. */
+    private static final int CNTR_CNT = 10;
+
+    /** Departments count */
+    private static final int DEP_CNT = 100;
+
+    /** Employees count. */
+    private static final int EMPL_CNT = 1000;
+
+    /** Countries count. */
+    private static final int CAR_CNT = 100;
+
+    /** Departments count */
+    private static final int PARK_CNT = 10;
+
+    /** Counter for threads in pool. */
+    private static final AtomicInteger THREAD_CNT = new AtomicInteger(0);
+
+    /**
+     * Create base cache configuration.
+     *
+     * @param name cache name.
+     * @return Cache configuration with basic properties set.
+     */
+    private static <K, V> CacheConfiguration<K, V> cacheConfiguration(String name) {
+        CacheConfiguration<K, V> ccfg = new CacheConfiguration<>(name);
+
+        ccfg.setAffinity(new RendezvousAffinityFunction(false, 32));
+        ccfg.setStartSize(100);
+        ccfg.setStatisticsEnabled(true);
+
+        return ccfg;
+    }
+
+    /**
+     * Configure cacheCountry.
+     */
+    private static <K, V> CacheConfiguration<K, V> cacheCountry() {
+        CacheConfiguration<K, V> ccfg = cacheConfiguration(COUNTRY_CACHE_NAME);
+
+        // Configure cacheCountry types.
+        Collection<QueryEntity> qryEntities = new ArrayList<>();
+
+        // COUNTRY.
+        QueryEntity type = new QueryEntity();
+
+        qryEntities.add(type);
+
+        type.setKeyType(Integer.class.getName());
+        type.setValueType(Country.class.getName());
+
+        // Query fields for COUNTRY.
+        LinkedHashMap<String, String> qryFlds = new LinkedHashMap<>();
+
+        qryFlds.put("id", "java.lang.Integer");
+        qryFlds.put("name", "java.lang.String");
+        qryFlds.put("population", "java.lang.Integer");
+
+        type.setFields(qryFlds);
+
+        ccfg.setQueryEntities(qryEntities);
+
+        return ccfg;
+    }
+
+    /**
+     * Configure cacheEmployee.
+     */
+    private static <K, V> CacheConfiguration<K, V> cacheDepartment() {
+        CacheConfiguration<K, V> ccfg = cacheConfiguration(DEPARTMENT_CACHE_NAME);
+
+        // Configure cacheDepartment types.
+        Collection<QueryEntity> qryEntities = new ArrayList<>();
+
+        // DEPARTMENT.
+        QueryEntity type = new QueryEntity();
+
+        qryEntities.add(type);
+
+        type.setKeyType(Integer.class.getName());
+        type.setValueType(Department.class.getName());
+
+        // Query fields for DEPARTMENT.
+        LinkedHashMap<String, String> qryFlds = new LinkedHashMap<>();
+
+        qryFlds.put("id", "java.lang.Integer");
+        qryFlds.put("countryId", "java.lang.Integer");
+        qryFlds.put("name", "java.lang.String");
+
+        type.setFields(qryFlds);
+
+        ccfg.setQueryEntities(qryEntities);
+
+        return ccfg;
+    }
+
+    /**
+     * Configure cacheEmployee.
+     */
+    private static <K, V> CacheConfiguration<K, V> cacheEmployee() {
+        CacheConfiguration<K, V> ccfg = cacheConfiguration(EMPLOYEE_CACHE_NAME);
+
+        ccfg.setAtomicityMode(CacheAtomicityMode.TRANSACTIONAL);
+        ccfg.setBackups(1);
+
+        // Configure cacheEmployee types.
+        Collection<QueryEntity> qryEntities = new ArrayList<>();
+
+        // EMPLOYEE.
+        QueryEntity type = new QueryEntity();
+
+        qryEntities.add(type);
+
+        type.setKeyType(Integer.class.getName());
+        type.setValueType(Employee.class.getName());
+
+        // Query fields for EMPLOYEE.
+        LinkedHashMap<String, String> qryFlds = new LinkedHashMap<>();
+
+        qryFlds.put("id", "java.lang.Integer");
+        qryFlds.put("departmentId", "java.lang.Integer");
+        qryFlds.put("managerId", "java.lang.Integer");
+        qryFlds.put("firstName", "java.lang.String");
+        qryFlds.put("lastName", "java.lang.String");
+        qryFlds.put("email", "java.lang.String");
+        qryFlds.put("phoneNumber", "java.lang.String");
+        qryFlds.put("hireDate", "java.sql.Date");
+        qryFlds.put("job", "java.lang.String");
+        qryFlds.put("salary", "java.lang.Double");
+
+        type.setFields(qryFlds);
+
+        // Indexes for EMPLOYEE.
+        Collection<QueryIndex> indexes = new ArrayList<>();
+
+        QueryIndex idx = new QueryIndex();
+
+        idx.setName("EMP_NAMES");
+        idx.setIndexType(QueryIndexType.SORTED);
+        LinkedHashMap<String, Boolean> indFlds = new LinkedHashMap<>();
+
+        indFlds.put("firstName", Boolean.FALSE);
+        indFlds.put("lastName", Boolean.FALSE);
+
+        idx.setFields(indFlds);
+
+        indexes.add(idx);
+        indexes.add(new QueryIndex("salary", QueryIndexType.SORTED, false, "EMP_SALARY"));
+
+        type.setIndexes(indexes);
+
+        ccfg.setQueryEntities(qryEntities);
+
+        return ccfg;
+    }
+
+    /**
+     * Configure cacheEmployee.
+     */
+    private static <K, V> CacheConfiguration<K, V> cacheParking() {
+        CacheConfiguration<K, V> ccfg = cacheConfiguration(PARKING_CACHE_NAME);
+
+        // Configure cacheParking types.
+        Collection<QueryEntity> qryEntities = new ArrayList<>();
+
+        // PARKING.
+        QueryEntity type = new QueryEntity();
+
+        qryEntities.add(type);
+
+        type.setKeyType(Integer.class.getName());
+        type.setValueType(Parking.class.getName());
+
+        // Query fields for PARKING.
+        LinkedHashMap<String, String> qryFlds = new LinkedHashMap<>();
+
+        qryFlds.put("id", "java.lang.Integer");
+        qryFlds.put("name", "java.lang.String");
+        qryFlds.put("capacity", "java.lang.Integer");
+
+        type.setFields(qryFlds);
+
+        ccfg.setQueryEntities(qryEntities);
+
+        return ccfg;
+    }
+
+    /**
+     * Configure cacheEmployee.
+     */
+    private static <K, V> CacheConfiguration<K, V> cacheCar() {
+        CacheConfiguration<K, V> ccfg = cacheConfiguration(CAR_CACHE_NAME);
+
+        // Configure cacheCar types.
+        Collection<QueryEntity> qryEntities = new ArrayList<>();
+
+        // CAR.
+        QueryEntity type = new QueryEntity();
+
+        qryEntities.add(type);
+
+        type.setKeyType(Integer.class.getName());
+        type.setValueType(Car.class.getName());
+
+        // Query fields for CAR.
+        LinkedHashMap<String, String> qryFlds = new LinkedHashMap<>();
+
+        qryFlds.put("id", "java.lang.Integer");
+        qryFlds.put("parkingId", "java.lang.Integer");
+        qryFlds.put("name", "java.lang.String");
+
+        type.setFields(qryFlds);
+
+        ccfg.setQueryEntities(qryEntities);
+
+        return ccfg;
+    }
+
+    /**
+     * Configure node.
+     * @param gridIdx Grid name index.
+     * @param client If {@code true} then start client node.
+     * @return IgniteConfiguration
+     */
+    private static  IgniteConfiguration igniteConfiguration(int gridIdx, boolean client) {
+        IgniteConfiguration cfg = new IgniteConfiguration();
+
+        cfg.setGridName((client ? "demo-server-" : "demo-client-") + gridIdx);
+        cfg.setLocalHost("127.0.0.1");
+        cfg.setIncludeEventTypes(EVTS_DISCOVERY);
+
+        TcpDiscoveryVmIpFinder ipFinder = new TcpDiscoveryVmIpFinder();
+
+        ipFinder.setAddresses(Collections.singletonList("127.0.0.1:60900.." + (60900 + NODE_CNT - 1)));
+
+        // Configure discovery SPI.
+        TcpDiscoverySpi discoSpi = new TcpDiscoverySpi();
+
+        discoSpi.setLocalPort(60900);
+        discoSpi.setIpFinder(ipFinder);
+
+        cfg.setDiscoverySpi(discoSpi);
+
+        TcpCommunicationSpi commSpi = new TcpCommunicationSpi();
+
+        commSpi.setSharedMemoryPort(-1);
+        commSpi.setLocalPort(60800);
+
+        cfg.setCommunicationSpi(commSpi);
+        cfg.setGridLogger(new Log4JLogger(log));
+        cfg.setMetricsLogFrequency(0);
+        cfg.getConnectorConfiguration().setPort(60700);
+
+        if (client)
+            cfg.setClientMode(true);
+
+        cfg.setCacheConfiguration(cacheCountry(), cacheDepartment(), cacheEmployee(), cacheParking(), cacheCar());
+
+        cfg.setSwapSpaceSpi(new FileSwapSpaceSpi());
+
+        return cfg;
+    }
+
+    /**
+     * @param val Value to round.
+     * @param places Numbers after point.
+     * @return Rounded value;
+     */
+    private static double round(double val, int places) {
+        if (places < 0)
+            throw new IllegalArgumentException();
+
+        long factor = (long)Math.pow(10, places);
+
+        val *= factor;
+
+        long tmp = Math.round(val);
+
+        return (double)tmp / factor;
+    }
+
+    /**
+     * @param ignite Ignite.
+     * @param range Time range in milliseconds.
+     */
+    private static void populateCacheEmployee(Ignite ignite, long range) {
+        if (log.isDebugEnabled())
+            log.debug("DEMO: Start employees population with data...");
+
+        IgniteCache<Integer, Country> cacheCountry = ignite.cache(COUNTRY_CACHE_NAME);
+
+        for (int i = 0, n = 1; i < CNTR_CNT; i++, n++)
+            cacheCountry.put(i, new Country(i, "Country #" + n, n * 10000000));
+
+        IgniteCache<Integer, Department> cacheDepartment = ignite.cache(DEPARTMENT_CACHE_NAME);
+
+        IgniteCache<Integer, Employee> cacheEmployee = ignite.cache(EMPLOYEE_CACHE_NAME);
+
+        for (int i = 0, n = 1; i < DEP_CNT; i++, n++) {
+            cacheDepartment.put(i, new Department(n, rnd.nextInt(CNTR_CNT), "Department #" + n));
+
+            double r = rnd.nextDouble();
+
+            cacheEmployee.put(i, new Employee(i, rnd.nextInt(DEP_CNT), null, "First name manager #" + n,
+                "Last name manager #" + n, "Email manager #" + n, "Phone number manager #" + n,
+                new java.sql.Date((long)(r * range)), "Job manager #" + n, 1000 + round(r * 4000, 2)));
+        }
+
+        for (int i = 0, n = 1; i < EMPL_CNT; i++, n++) {
+            Integer depId = rnd.nextInt(DEP_CNT);
+
+            double r = rnd.nextDouble();
+
+            cacheEmployee.put(i, new Employee(i, depId, depId, "First name employee #" + n,
+                "Last name employee #" + n, "Email employee #" + n, "Phone number employee #" + n,
+                new java.sql.Date((long)(r * range)), "Job employee #" + n, 500 + round(r * 2000, 2)));
+        }
+
+        if (log.isDebugEnabled())
+            log.debug("DEMO: Finished employees population.");
+    }
+
+    /**
+     * @param ignite Ignite.
+     */
+    private static void populateCacheCar(Ignite ignite) {
+        if (log.isDebugEnabled())
+            log.debug("DEMO: Start cars population...");
+
+        IgniteCache<Integer, Parking> cacheParking = ignite.cache(PARKING_CACHE_NAME);
+
+        for (int i = 0, n = 1; i < PARK_CNT; i++, n++)
+            cacheParking.put(i, new Parking(i, "Parking #" + n, n * 10));
+
+        IgniteCache<Integer, Car> cacheCar = ignite.cache(CAR_CACHE_NAME);
+
+        for (int i = 0, n = 1; i < CAR_CNT; i++, n++)
+            cacheCar.put(i, new Car(i, rnd.nextInt(PARK_CNT), "Car #" + n));
+
+        if (log.isDebugEnabled())
+            log.debug("DEMO: Finished cars population.");
+    }
+
+    /**
+     * Creates a thread pool that can schedule commands to run after a given delay, or to execute periodically.
+     *
+     * @param corePoolSize Number of threads to keep in the pool, even if they are idle.
+     * @param threadName Part of thread name that would be used by thread factory.
+     * @return Newly created scheduled thread pool.
+     */
+    private static ScheduledExecutorService newScheduledThreadPool(int corePoolSize, final String threadName) {
+        ScheduledExecutorService srvc = Executors.newScheduledThreadPool(corePoolSize, new ThreadFactory() {
+            @Override public Thread newThread(Runnable r) {
+                Thread thread = new Thread(r, String.format("%s-%d", threadName, THREAD_CNT.getAndIncrement()));
+
+                thread.setDaemon(true);
+
+                return thread;
+            }
+        });
+
+        ScheduledThreadPoolExecutor executor = (ScheduledThreadPoolExecutor)srvc;
+
+        // Setting up shutdown policy.
+        executor.setExecuteExistingDelayedTasksAfterShutdownPolicy(false);
+        executor.setContinueExistingPeriodicTasksAfterShutdownPolicy(false);
+
+        return srvc;
+    }
+
+    /**
+     * Starts read and write from cache in background.
+     *
+     * @param ignite Ignite.
+     * @param cnt - maximum count read/write key
+     */
+    private static void startLoad(final Ignite ignite, final int cnt) {
+        final long diff = new java.util.Date().getTime();
+
+        populateCacheEmployee(ignite, diff);
+        populateCacheCar(ignite);
+
+        ScheduledExecutorService cachePool = newScheduledThreadPool(2, "demo-sql-load-cache-tasks");
+
+        cachePool.scheduleWithFixedDelay(new Runnable() {
+            @Override public void run() {
+                try {
+                    for (String cacheName : ignite.cacheNames()) {
+                        if (!DEMO_CACHES.contains(cacheName)) {
+                            IgniteCache<Integer, String> otherCache = ignite.cache(cacheName);
+
+                            if (otherCache != null) {
+                                for (int i = 0, n = 1; i < cnt; i++, n++) {
+                                    Integer key = rnd.nextInt(1000);
+
+                                    String val = otherCache.get(key);
+
+                                    if (val == null)
+                                        otherCache.put(key, "other-" + key);
+                                    else if (rnd.nextInt(100) < 30)
+                                        otherCache.remove(key);
+                                }
+                            }
+                        }
+                    }
+
+                    IgniteCache<Integer, Employee> cacheEmployee = ignite.cache(EMPLOYEE_CACHE_NAME);
+
+                    if (cacheEmployee != null)
+                        try(Transaction tx = ignite.transactions().txStart(PESSIMISTIC, REPEATABLE_READ)) {
+                            for (int i = 0, n = 1; i < cnt; i++, n++) {
+                                Integer id = rnd.nextInt(EMPL_CNT);
+
+                                Integer depId = rnd.nextInt(DEP_CNT);
+
+                                double r = rnd.nextDouble();
+
+                                cacheEmployee.put(id, new Employee(id, depId, depId, "First name employee #" + n,
+                                    "Last name employee #" + n, "Email employee #" + n, "Phone number employee #" + n,
+                                    new java.sql.Date((long)(r * diff)), "Job employee #" + n, 500 + round(r * 2000, 2)));
+
+                                if (rnd.nextBoolean())
+                                    cacheEmployee.remove(rnd.nextInt(EMPL_CNT));
+
+                                cacheEmployee.get(rnd.nextInt(EMPL_CNT));
+                            }
+
+                            if (rnd.nextInt(100) > 20)
+                                tx.commit();
+                        }
+                }
+                catch (Throwable e) {
+                    if (!e.getMessage().contains("cache is stopped"))
+                        ignite.log().error("Cache write task execution error", e);
+                }
+            }
+        }, 10, 3, TimeUnit.SECONDS);
+
+        cachePool.scheduleWithFixedDelay(new Runnable() {
+            @Override public void run() {
+                try {
+                    IgniteCache<Integer, Car> cache = ignite.cache(CAR_CACHE_NAME);
+
+                    if (cache != null)
+                        for (int i = 0; i < cnt; i++) {
+                            Integer carId = rnd.nextInt(CAR_CNT);
+
+                            cache.put(carId, new Car(carId, rnd.nextInt(PARK_CNT), "Car #" + (i + 1)));
+
+                            if (rnd.nextBoolean())
+                                cache.remove(rnd.nextInt(CAR_CNT));
+                        }
+                }
+                catch (IllegalStateException ignored) {
+                    // No-op.
+                }
+                catch (Throwable e) {
+                    if (!e.getMessage().contains("cache is stopped"))
+                        ignite.log().error("Cache write task execution error", e);
+                }
+            }
+        }, 10, 3, TimeUnit.SECONDS);
+    }
+
+    /**
+     * Start ignite node with cacheEmployee and populate it with data.
+     */
+    public static boolean testDrive(AgentConfiguration acfg) {
+        if (initLatch.compareAndSet(false, true)) {
+            log.info("DEMO: Starting embedded nodes for demo...");
+
+            System.setProperty(IGNITE_ATOMIC_CACHE_DELETE_HISTORY_SIZE, "1");
+            System.setProperty(IGNITE_PERFORMANCE_SUGGESTIONS_DISABLED, "true");
+            System.setProperty(IGNITE_UPDATE_NOTIFIER, "false");
+
+            System.setProperty(IGNITE_JETTY_PORT, "60800");
+            System.setProperty(IGNITE_NO_ASCII, "true");
+
+            try {
+                IgniteEx ignite = (IgniteEx)Ignition.start(igniteConfiguration(0, false));
+
+                final AtomicInteger cnt = new AtomicInteger(0);
+
+                final ScheduledExecutorService execSrv = Executors.newSingleThreadScheduledExecutor();
+
+                execSrv.scheduleAtFixedRate(new Runnable() {
+                    @Override public void run() {
+                        int idx = cnt.incrementAndGet();
+
+                        try {
+                            Ignition.start(igniteConfiguration(idx, idx == NODE_CNT));
+                        }
+                        catch (Throwable e) {
+                            log.error("DEMO: Failed to start embedded node: " + e.getMessage());
+                        }
+                        finally {
+                            if (idx == NODE_CNT)
+                                execSrv.shutdown();
+                        }
+                    }
+                }, 10, 10, TimeUnit.SECONDS);
+
+                if (log.isDebugEnabled())
+                    log.debug("DEMO: Started embedded nodes with indexed enabled caches...");
+
+                Collection<String> jettyAddrs = ignite.localNode().attribute(ATTR_REST_JETTY_ADDRS);
+
+                String host = jettyAddrs == null ? null : jettyAddrs.iterator().next();
+
+                Integer port = ignite.localNode().attribute(ATTR_REST_JETTY_PORT);
+
+                if (F.isEmpty(host) || port == null) {
+                    log.error("DEMO: Failed to start embedded node with rest!");
+
+                    return false;
+                }
+
+                acfg.demoNodeUri(String.format("http://%s:%d", host, port));
+
+                log.info("DEMO: Embedded nodes for sql and monitoring demo successfully started");
+
+                startLoad(ignite, 20);
+            }
+            catch (Exception e) {
+                log.error("DEMO: Failed to start embedded node for sql and monitoring demo!", e);
+
+                return false;
+            }
+        }
+
+        return true;
+    }
+}

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/web-agent/src/main/java/org/apache/ignite/console/demo/AgentMetadataDemo.java
----------------------------------------------------------------------
diff --git a/modules/web-console/web-agent/src/main/java/org/apache/ignite/console/demo/AgentMetadataDemo.java b/modules/web-console/web-agent/src/main/java/org/apache/ignite/console/demo/AgentMetadataDemo.java
new file mode 100644
index 0000000..4683dd8
--- /dev/null
+++ b/modules/web-console/web-agent/src/main/java/org/apache/ignite/console/demo/AgentMetadataDemo.java
@@ -0,0 +1,92 @@
+/*
+ * 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.
+ */
+
+package org.apache.ignite.console.demo;
+
+import java.io.File;
+import java.io.FileNotFoundException;
+import java.io.FileReader;
+import java.sql.Connection;
+import java.sql.DriverManager;
+import java.sql.SQLException;
+import java.util.concurrent.atomic.AtomicBoolean;
+import org.apache.log4j.Logger;
+import org.h2.tools.RunScript;
+import org.h2.tools.Server;
+
+import static org.apache.ignite.console.agent.AgentUtils.resolvePath;
+
+/**
+ * Demo for metadata load from database.
+ *
+ * H2 database will be started and several tables will be created.
+ */
+public class AgentMetadataDemo {
+    /** */
+    private static final Logger log = Logger.getLogger(AgentMetadataDemo.class.getName());
+
+    /** */
+    private static final AtomicBoolean initLatch = new AtomicBoolean();
+
+    /**
+     * @param jdbcUrl Connection url.
+     * @return true if url is used for test-drive.
+     */
+    public static boolean isTestDriveUrl(String jdbcUrl) {
+        return "jdbc:h2:mem:demo-db".equals(jdbcUrl);
+    }
+
+    /**
+     * Start H2 database and populate it with several tables.
+     */
+    public static Connection testDrive() throws SQLException {
+        if (initLatch.compareAndSet(false, true)) {
+            log.info("DEMO: Prepare in-memory H2 database...");
+
+            try {
+                Connection conn = DriverManager.getConnection("jdbc:h2:mem:demo-db;DB_CLOSE_DELAY=-1", "sa", "");
+
+                File sqlScript = resolvePath("demo/db-init.sql");
+
+                //noinspection ConstantConditions
+                RunScript.execute(conn, new FileReader(sqlScript));
+
+                log.info("DEMO: Sample tables created.");
+
+                conn.close();
+
+                Server.createTcpServer("-tcpDaemon").start();
+
+                log.info("DEMO: TcpServer stared.");
+
+                log.info("DEMO: JDBC URL for test drive metadata load: jdbc:h2:mem:demo-db");
+            }
+            catch (SQLException e) {
+                log.error("DEMO: Failed to start test drive for metadata!", e);
+
+                throw e;
+            }
+            catch (FileNotFoundException | NullPointerException e) {
+                log.error("DEMO: Failed to find demo database init script file: demo/db-init.sql");
+
+                throw new SQLException("Failed to start demo for metadata", e);
+            }
+        }
+
+        return DriverManager.getConnection("jdbc:h2:mem:demo-db;DB_CLOSE_DELAY=-1", "sa", "");
+    }
+}

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/web-agent/src/main/java/org/apache/ignite/console/demo/model/Car.java
----------------------------------------------------------------------
diff --git a/modules/web-console/web-agent/src/main/java/org/apache/ignite/console/demo/model/Car.java b/modules/web-console/web-agent/src/main/java/org/apache/ignite/console/demo/model/Car.java
new file mode 100644
index 0000000..f351efc
--- /dev/null
+++ b/modules/web-console/web-agent/src/main/java/org/apache/ignite/console/demo/model/Car.java
@@ -0,0 +1,152 @@
+/*
+ * 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.
+ */
+
+package org.apache.ignite.console.demo.model;
+
+import java.io.Serializable;
+
+/**
+ * Car definition.
+ */
+public class Car implements Serializable {
+    /** */
+    private static final long serialVersionUID = 0L;
+
+    /** Value for id. */
+    private int id;
+
+    /** Value for parkingId. */
+    private int parkingId;
+
+    /** Value for name. */
+    private String name;
+
+    /**
+     * Empty constructor.
+     */
+    public Car() {
+        // No-op.
+    }
+
+    /**
+     * Full constructor.
+     */
+    public Car(
+        int id,
+        int parkingId,
+        String name
+    ) {
+        this.id = id;
+        this.parkingId = parkingId;
+        this.name = name;
+    }
+
+    /**
+     * Gets id.
+     *
+     * @return Value for id.
+     */
+    public int getId() {
+        return id;
+    }
+
+    /**
+     * Sets id.
+     *
+     * @param id New value for id.
+     */
+    public void setId(int id) {
+        this.id = id;
+    }
+
+    /**
+     * Gets parkingId.
+     *
+     * @return Value for parkingId.
+     */
+    public int getParkingId() {
+        return parkingId;
+    }
+
+    /**
+     * Sets parkingId.
+     *
+     * @param parkingId New value for parkingId.
+     */
+    public void setParkingId(int parkingId) {
+        this.parkingId = parkingId;
+    }
+
+    /**
+     * Gets name.
+     *
+     * @return Value for name.
+     */
+    public String getName() {
+        return name;
+    }
+
+    /**
+     * Sets name.
+     *
+     * @param name New value for name.
+     */
+    public void setName(String name) {
+        this.name = name;
+    }
+
+    /** {@inheritDoc} */
+    @Override public boolean equals(Object o) {
+        if (this == o)
+            return true;
+        
+        if (!(o instanceof Car))
+            return false;
+
+        Car that = (Car)o;
+
+        if (id != that.id)
+            return false;
+
+        if (parkingId != that.parkingId)
+            return false;
+
+        if (name != null ? !name.equals(that.name) : that.name != null)
+            return false;
+
+        return true;
+    }
+
+    /** {@inheritDoc} */
+    @Override public int hashCode() {
+        int res = id;
+
+        res = 31 * res + parkingId;
+
+        res = 31 * res + (name != null ? name.hashCode() : 0);
+
+        return res;
+    }
+
+    /** {@inheritDoc} */
+    @Override public String toString() {
+        return "Car [id=" + id +
+            ", parkingId=" + parkingId +
+            ", name=" + name +
+            ']';
+    }
+}

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/web-agent/src/main/java/org/apache/ignite/console/demo/model/Country.java
----------------------------------------------------------------------
diff --git a/modules/web-console/web-agent/src/main/java/org/apache/ignite/console/demo/model/Country.java b/modules/web-console/web-agent/src/main/java/org/apache/ignite/console/demo/model/Country.java
new file mode 100644
index 0000000..348928b
--- /dev/null
+++ b/modules/web-console/web-agent/src/main/java/org/apache/ignite/console/demo/model/Country.java
@@ -0,0 +1,152 @@
+/*
+ * 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.
+ */
+
+package org.apache.ignite.console.demo.model;
+
+import java.io.Serializable;
+
+/**
+ * Country definition.
+ */
+public class Country implements Serializable {
+    /** */
+    private static final long serialVersionUID = 0L;
+
+    /** Value for id. */
+    private int id;
+
+    /** Value for name. */
+    private String name;
+
+    /** Value for population. */
+    private int population;
+
+    /**
+     * Empty constructor.
+     */
+    public Country() {
+        // No-op.
+    }
+
+    /**
+     * Full constructor.
+     */
+    public Country(
+        int id,
+        String name,
+        int population
+    ) {
+        this.id = id;
+        this.name = name;
+        this.population = population;
+    }
+
+    /**
+     * Gets id.
+     *
+     * @return Value for id.
+     */
+    public int getId() {
+        return id;
+    }
+
+    /**
+     * Sets id.
+     *
+     * @param id New value for id.
+     */
+    public void setId(int id) {
+        this.id = id;
+    }
+
+    /**
+     * Gets name.
+     *
+     * @return Value for name.
+     */
+    public String getName() {
+        return name;
+    }
+
+    /**
+     * Sets name.
+     *
+     * @param name New value for name.
+     */
+    public void setName(String name) {
+        this.name = name;
+    }
+
+    /**
+     * Gets population.
+     *
+     * @return Value for population.
+     */
+    public int getPopulation() {
+        return population;
+    }
+
+    /**
+     * Sets population.
+     *
+     * @param population New value for population.
+     */
+    public void setPopulation(int population) {
+        this.population = population;
+    }
+
+    /** {@inheritDoc} */
+    @Override public boolean equals(Object o) {
+        if (this == o)
+            return true;
+        
+        if (!(o instanceof Country))
+            return false;
+
+        Country that = (Country)o;
+
+        if (id != that.id)
+            return false;
+
+        if (name != null ? !name.equals(that.name) : that.name != null)
+            return false;
+
+        if (population != that.population)
+            return false;
+
+        return true;
+    }
+
+    /** {@inheritDoc} */
+    @Override public int hashCode() {
+        int res = id;
+
+        res = 31 * res + (name != null ? name.hashCode() : 0);
+
+        res = 31 * res + population;
+
+        return res;
+    }
+
+    /** {@inheritDoc} */
+    @Override public String toString() {
+        return "Country [id=" + id +
+            ", name=" + name +
+            ", population=" + population +
+            ']';
+    }
+}

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/web-agent/src/main/java/org/apache/ignite/console/demo/model/Department.java
----------------------------------------------------------------------
diff --git a/modules/web-console/web-agent/src/main/java/org/apache/ignite/console/demo/model/Department.java b/modules/web-console/web-agent/src/main/java/org/apache/ignite/console/demo/model/Department.java
new file mode 100644
index 0000000..1c2f3b2
--- /dev/null
+++ b/modules/web-console/web-agent/src/main/java/org/apache/ignite/console/demo/model/Department.java
@@ -0,0 +1,152 @@
+/*
+ * 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.
+ */
+
+package org.apache.ignite.console.demo.model;
+
+import java.io.Serializable;
+
+/**
+ * Department definition.
+ */
+public class Department implements Serializable {
+    /** */
+    private static final long serialVersionUID = 0L;
+
+    /** Value for id. */
+    private int id;
+
+    /** Value for countryId. */
+    private int countryId;
+
+    /** Value for name. */
+    private String name;
+
+    /**
+     * Empty constructor.
+     */
+    public Department() {
+        // No-op.
+    }
+
+    /**
+     * Full constructor.
+     */
+    public Department(
+        int id,
+        int countryId,
+        String name
+    ) {
+        this.id = id;
+        this.countryId = countryId;
+        this.name = name;
+    }
+
+    /**
+     * Gets id.
+     *
+     * @return Value for id.
+     */
+    public int getId() {
+        return id;
+    }
+
+    /**
+     * Sets id.
+     *
+     * @param id New value for id.
+     */
+    public void setId(int id) {
+        this.id = id;
+    }
+
+    /**
+     * Gets countryId.
+     *
+     * @return Value for countryId.
+     */
+    public int getCountryId() {
+        return countryId;
+    }
+
+    /**
+     * Sets countryId.
+     *
+     * @param countryId New value for countryId.
+     */
+    public void setCountryId(int countryId) {
+        this.countryId = countryId;
+    }
+
+    /**
+     * Gets name.
+     *
+     * @return Value for name.
+     */
+    public String getName() {
+        return name;
+    }
+
+    /**
+     * Sets name.
+     *
+     * @param name New value for name.
+     */
+    public void setName(String name) {
+        this.name = name;
+    }
+
+    /** {@inheritDoc} */
+    @Override public boolean equals(Object o) {
+        if (this == o)
+            return true;
+        
+        if (!(o instanceof Department))
+            return false;
+
+        Department that = (Department)o;
+
+        if (id != that.id)
+            return false;
+
+        if (countryId != that.countryId)
+            return false;
+
+        if (name != null ? !name.equals(that.name) : that.name != null)
+            return false;
+
+        return true;
+    }
+
+    /** {@inheritDoc} */
+    @Override public int hashCode() {
+        int res = id;
+
+        res = 31 * res + countryId;
+
+        res = 31 * res + (name != null ? name.hashCode() : 0);
+
+        return res;
+    }
+
+    /** {@inheritDoc} */
+    @Override public String toString() {
+        return "Department [id=" + id +
+            ", countryId=" + countryId +
+            ", name=" + name +
+            ']';
+    }
+}

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/web-agent/src/main/java/org/apache/ignite/console/demo/model/Employee.java
----------------------------------------------------------------------
diff --git a/modules/web-console/web-agent/src/main/java/org/apache/ignite/console/demo/model/Employee.java b/modules/web-console/web-agent/src/main/java/org/apache/ignite/console/demo/model/Employee.java
new file mode 100644
index 0000000..a3e7eba
--- /dev/null
+++ b/modules/web-console/web-agent/src/main/java/org/apache/ignite/console/demo/model/Employee.java
@@ -0,0 +1,356 @@
+/*
+ * 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.
+ */
+
+package org.apache.ignite.console.demo.model;
+
+import java.io.Serializable;
+import java.sql.Date;
+
+/**
+ * Employee definition.
+ */
+public class Employee implements Serializable {
+    /** */
+    private static final long serialVersionUID = 0L;
+
+    /** Value for id. */
+    private int id;
+
+    /** Value for departmentId. */
+    private int departmentId;
+
+    /** Value for managerId. */
+    private Integer managerId;
+
+    /** Value for firstName. */
+    private String firstName;
+
+    /** Value for lastName. */
+    private String lastName;
+
+    /** Value for email. */
+    private String email;
+
+    /** Value for phoneNumber. */
+    private String phoneNumber;
+
+    /** Value for hireDate. */
+    private Date hireDate;
+
+    /** Value for job. */
+    private String job;
+
+    /** Value for salary. */
+    private Double salary;
+
+    /**
+     * Empty constructor.
+     */
+    public Employee() {
+        // No-op.
+    }
+
+    /**
+     * Full constructor.
+     */
+    public Employee(
+        int id,
+        int departmentId,
+        Integer managerId,
+        String firstName,
+        String lastName,
+        String email,
+        String phoneNumber,
+        Date hireDate,
+        String job,
+        Double salary
+    ) {
+        this.id = id;
+        this.departmentId = departmentId;
+        this.managerId = managerId;
+        this.firstName = firstName;
+        this.lastName = lastName;
+        this.email = email;
+        this.phoneNumber = phoneNumber;
+        this.hireDate = hireDate;
+        this.job = job;
+        this.salary = salary;
+    }
+
+    /**
+     * Gets id.
+     *
+     * @return Value for id.
+     */
+    public int getId() {
+        return id;
+    }
+
+    /**
+     * Sets id.
+     *
+     * @param id New value for id.
+     */
+    public void setId(int id) {
+        this.id = id;
+    }
+
+    /**
+     * Gets departmentId.
+     *
+     * @return Value for departmentId.
+     */
+    public int getDepartmentId() {
+        return departmentId;
+    }
+
+    /**
+     * Sets departmentId.
+     *
+     * @param departmentId New value for departmentId.
+     */
+    public void setDepartmentId(int departmentId) {
+        this.departmentId = departmentId;
+    }
+
+    /**
+     * Gets managerId.
+     *
+     * @return Value for managerId.
+     */
+    public Integer getManagerId() {
+        return managerId;
+    }
+
+    /**
+     * Sets managerId.
+     *
+     * @param managerId New value for managerId.
+     */
+    public void setManagerId(Integer managerId) {
+        this.managerId = managerId;
+    }
+
+    /**
+     * Gets firstName.
+     *
+     * @return Value for firstName.
+     */
+    public String getFirstName() {
+        return firstName;
+    }
+
+    /**
+     * Sets firstName.
+     *
+     * @param firstName New value for firstName.
+     */
+    public void setFirstName(String firstName) {
+        this.firstName = firstName;
+    }
+
+    /**
+     * Gets lastName.
+     *
+     * @return Value for lastName.
+     */
+    public String getLastName() {
+        return lastName;
+    }
+
+    /**
+     * Sets lastName.
+     *
+     * @param lastName New value for lastName.
+     */
+    public void setLastName(String lastName) {
+        this.lastName = lastName;
+    }
+
+    /**
+     * Gets email.
+     *
+     * @return Value for email.
+     */
+    public String getEmail() {
+        return email;
+    }
+
+    /**
+     * Sets email.
+     *
+     * @param email New value for email.
+     */
+    public void setEmail(String email) {
+        this.email = email;
+    }
+
+    /**
+     * Gets phoneNumber.
+     *
+     * @return Value for phoneNumber.
+     */
+    public String getPhoneNumber() {
+        return phoneNumber;
+    }
+
+    /**
+     * Sets phoneNumber.
+     *
+     * @param phoneNumber New value for phoneNumber.
+     */
+    public void setPhoneNumber(String phoneNumber) {
+        this.phoneNumber = phoneNumber;
+    }
+
+    /**
+     * Gets hireDate.
+     *
+     * @return Value for hireDate.
+     */
+    public Date getHireDate() {
+        return hireDate;
+    }
+
+    /**
+     * Sets hireDate.
+     *
+     * @param hireDate New value for hireDate.
+     */
+    public void setHireDate(Date hireDate) {
+        this.hireDate = hireDate;
+    }
+
+    /**
+     * Gets job.
+     *
+     * @return Value for job.
+     */
+    public String getJob() {
+        return job;
+    }
+
+    /**
+     * Sets job.
+     *
+     * @param job New value for job.
+     */
+    public void setJob(String job) {
+        this.job = job;
+    }
+
+    /**
+     * Gets salary.
+     *
+     * @return Value for salary.
+     */
+    public Double getSalary() {
+        return salary;
+    }
+
+    /**
+     * Sets salary.
+     *
+     * @param salary New value for salary.
+     */
+    public void setSalary(Double salary) {
+        this.salary = salary;
+    }
+
+    /** {@inheritDoc} */
+    @Override public boolean equals(Object o) {
+        if (this == o)
+            return true;
+        
+        if (!(o instanceof Employee))
+            return false;
+
+        Employee that = (Employee)o;
+
+        if (id != that.id)
+            return false;
+
+        if (departmentId != that.departmentId)
+            return false;
+
+        if (managerId != null ? !managerId.equals(that.managerId) : that.managerId != null)
+            return false;
+
+        if (firstName != null ? !firstName.equals(that.firstName) : that.firstName != null)
+            return false;
+
+        if (lastName != null ? !lastName.equals(that.lastName) : that.lastName != null)
+            return false;
+
+        if (email != null ? !email.equals(that.email) : that.email != null)
+            return false;
+
+        if (phoneNumber != null ? !phoneNumber.equals(that.phoneNumber) : that.phoneNumber != null)
+            return false;
+
+        if (hireDate != null ? !hireDate.equals(that.hireDate) : that.hireDate != null)
+            return false;
+
+        if (job != null ? !job.equals(that.job) : that.job != null)
+            return false;
+
+        if (salary != null ? !salary.equals(that.salary) : that.salary != null)
+            return false;
+
+        return true;
+    }
+
+    /** {@inheritDoc} */
+    @Override public int hashCode() {
+        int res = id;
+
+        res = 31 * res + departmentId;
+
+        res = 31 * res + (managerId != null ? managerId.hashCode() : 0);
+
+        res = 31 * res + (firstName != null ? firstName.hashCode() : 0);
+
+        res = 31 * res + (lastName != null ? lastName.hashCode() : 0);
+
+        res = 31 * res + (email != null ? email.hashCode() : 0);
+
+        res = 31 * res + (phoneNumber != null ? phoneNumber.hashCode() : 0);
+
+        res = 31 * res + (hireDate != null ? hireDate.hashCode() : 0);
+
+        res = 31 * res + (job != null ? job.hashCode() : 0);
+
+        res = 31 * res + (salary != null ? salary.hashCode() : 0);
+
+        return res;
+    }
+
+    /** {@inheritDoc} */
+    @Override public String toString() {
+        return "Employee [id=" + id +
+            ", departmentId=" + departmentId +
+            ", managerId=" + managerId +
+            ", firstName=" + firstName +
+            ", lastName=" + lastName +
+            ", email=" + email +
+            ", phoneNumber=" + phoneNumber +
+            ", hireDate=" + hireDate +
+            ", job=" + job +
+            ", salary=" + salary +
+            ']';
+    }
+}

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/web-agent/src/main/java/org/apache/ignite/console/demo/model/Parking.java
----------------------------------------------------------------------
diff --git a/modules/web-console/web-agent/src/main/java/org/apache/ignite/console/demo/model/Parking.java b/modules/web-console/web-agent/src/main/java/org/apache/ignite/console/demo/model/Parking.java
new file mode 100644
index 0000000..d55ae81
--- /dev/null
+++ b/modules/web-console/web-agent/src/main/java/org/apache/ignite/console/demo/model/Parking.java
@@ -0,0 +1,152 @@
+/*
+ * 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.
+ */
+
+package org.apache.ignite.console.demo.model;
+
+import java.io.Serializable;
+
+/**
+ * Parking definition.
+ */
+public class Parking implements Serializable {
+    /** */
+    private static final long serialVersionUID = 0L;
+
+    /** Value for id. */
+    private int id;
+
+    /** Value for name. */
+    private String name;
+
+    /** Value for capacity. */
+    private int capacity;
+
+    /**
+     * Empty constructor.
+     */
+    public Parking() {
+        // No-op.
+    }
+
+    /**
+     * Full constructor.
+     */
+    public Parking(
+        int id,
+        String name,
+        int capacity
+    ) {
+        this.id = id;
+        this.name = name;
+        this.capacity = capacity;
+    }
+
+    /**
+     * Gets id.
+     *
+     * @return Value for id.
+     */
+    public int getId() {
+        return id;
+    }
+
+    /**
+     * Sets id.
+     *
+     * @param id New value for id.
+     */
+    public void setId(int id) {
+        this.id = id;
+    }
+
+    /**
+     * Gets name.
+     *
+     * @return Value for name.
+     */
+    public String getName() {
+        return name;
+    }
+
+    /**
+     * Sets name.
+     *
+     * @param name New value for name.
+     */
+    public void setName(String name) {
+        this.name = name;
+    }
+
+    /**
+     * Gets capacity.
+     *
+     * @return Value for capacity.
+     */
+    public int getCapacity() {
+        return capacity;
+    }
+
+    /**
+     * Sets capacity.
+     *
+     * @param capacity New value for capacity.
+     */
+    public void setCapacity(int capacity) {
+        this.capacity = capacity;
+    }
+
+    /** {@inheritDoc} */
+    @Override public boolean equals(Object o) {
+        if (this == o)
+            return true;
+        
+        if (!(o instanceof Parking))
+            return false;
+
+        Parking that = (Parking)o;
+
+        if (id != that.id)
+            return false;
+
+        if (name != null ? !name.equals(that.name) : that.name != null)
+            return false;
+
+        if (capacity != that.capacity)
+            return false;
+
+        return true;
+    }
+
+    /** {@inheritDoc} */
+    @Override public int hashCode() {
+        int res = id;
+
+        res = 31 * res + (name != null ? name.hashCode() : 0);
+
+        res = 31 * res + capacity;
+
+        return res;
+    }
+
+    /** {@inheritDoc} */
+    @Override public String toString() {
+        return "Parking [id=" + id +
+            ", name=" + name +
+            ", capacity=" + capacity +
+            ']';
+    }
+}

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/web-agent/src/main/resources/log4j.properties
----------------------------------------------------------------------
diff --git a/modules/web-console/web-agent/src/main/resources/log4j.properties b/modules/web-console/web-agent/src/main/resources/log4j.properties
new file mode 100644
index 0000000..3b7767c
--- /dev/null
+++ b/modules/web-console/web-agent/src/main/resources/log4j.properties
@@ -0,0 +1,53 @@
+# 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.
+
+log4j.rootLogger=INFO,console_err,file
+
+log4j.logger.org.apache.http=WARN
+log4j.logger.org.apache.ignite.spi.checkpoint.noop.NoopCheckpointSpi=OFF
+log4j.logger.org.apache.ignite.spi.swapspace.noop.NoopSwapSpaceSpi=OFF
+log4j.logger.org.apache.ignite.internal.managers.collision.GridCollisionManager=ERROR
+log4j.logger.org.apache.commons.beanutils=WARN
+log4j.logger.sun.net.www.protocol.http=WARN
+
+# Configure console appender.
+log4j.appender.console_err=org.apache.log4j.ConsoleAppender
+log4j.appender.console_err.Threshold=WARN
+log4j.appender.console_err.layout=org.apache.log4j.PatternLayout
+log4j.appender.console_err.layout.ConversionPattern=[%d{ABSOLUTE}][%-5p][%t][%c{1}] %m%n
+
+# Configure console appender.
+log4j.appender.console=org.apache.log4j.ConsoleAppender
+log4j.appender.console.layout=org.apache.log4j.PatternLayout
+log4j.appender.console.layout.ConversionPattern=[%d{ABSOLUTE}][%-5p][%t][%c{1}] %m%n
+log4j.appender.console.filter.a=org.apache.log4j.varia.LevelMatchFilter
+log4j.appender.console.filter.a.LevelToMatch=INFO
+log4j.appender.console.filter.a.AcceptOnMatch=true
+log4j.appender.console.filter.b=org.apache.log4j.varia.LevelMatchFilter
+log4j.appender.console.filter.b.LevelToMatch=ERROR
+log4j.appender.console.filter.b.AcceptOnMatch=false
+log4j.appender.console.filter.c=org.apache.log4j.varia.LevelMatchFilter
+log4j.appender.console.filter.c.LevelToMatch=WARN
+log4j.appender.console.filter.c.AcceptOnMatch=false
+
+log4j.category.org.apache.ignite.console=INFO,console
+
+# Direct log messages to a log file
+log4j.appender.file=org.apache.log4j.RollingFileAppender
+log4j.appender.file.File=logs/ignite-web-agent.log
+log4j.appender.file.MaxFileSize=10MB
+log4j.appender.file.MaxBackupIndex=10
+log4j.appender.file.layout=org.apache.log4j.PatternLayout
+log4j.appender.file.layout.ConversionPattern=[%d{ABSOLUTE}][%-5p][%t][%c{1}] %m%n

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/pom.xml
----------------------------------------------------------------------
diff --git a/pom.xml b/pom.xml
index 2c7bad1..070b5c8 100644
--- a/pom.xml
+++ b/pom.xml
@@ -798,8 +798,8 @@
         <profile>
             <id>web-console</id>
             <modules>
-                <module>modules/web-agent</module>
                 <module>modules/web-console</module>
+                <module>modules/web-console/web-agent</module>
                 <module>modules/schema-import-db</module>
             </modules>
         </profile>


[16/52] ignite git commit: Web Console beta-3.

Posted by ak...@apache.org.
http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/src/main/js/app/modules/states/configuration/clusters/deployment.jade
----------------------------------------------------------------------
diff --git a/modules/web-console/src/main/js/app/modules/states/configuration/clusters/deployment.jade b/modules/web-console/src/main/js/app/modules/states/configuration/clusters/deployment.jade
deleted file mode 100644
index 98e7f61..0000000
--- a/modules/web-console/src/main/js/app/modules/states/configuration/clusters/deployment.jade
+++ /dev/null
@@ -1,119 +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.
-
-include ../../../../../app/helpers/jade/mixins.jade
-
--var form = 'deployment'
--var model = 'backupItem'
--var exclude = model + '.peerClassLoadingLocalClassPathExclude'
--var enabled = 'backupItem.peerClassLoadingEnabled'
-
-form.panel.panel-default(name='deployment' novalidate)
-    .panel-heading(bs-collapse-toggle ng-click='ui.loadPanel("#{form}")')
-        ignite-form-panel-chevron
-        label Class deployment
-        ignite-form-field-tooltip.tipLabel
-            | Task and resources deployment in cluster
-        ignite-form-revert
-    .panel-collapse(role='tabpanel' bs-collapse-target id='deployment')
-        .panel-body(ng-if='ui.isPanelLoaded("#{form}")')
-            .col-sm-6
-                .settings-row
-                    +dropdown('Deployment mode:', model + '.deploymentMode', 'deploymentMode', 'true', 'SHARED',
-                        '[\
-                            {value: "PRIVATE", label: "PRIVATE"},\
-                            {value: "ISOLATED", label: "ISOLATED"}, \
-                            {value: "SHARED", label: "SHARED"},\
-                            {value: "CONTINUOUS", label: "CONTINUOUS"}\
-                        ]',
-                        'Task classes and resources sharing mode<br/>\
-                        The following deployment modes are supported:\
-                        <ul>\
-                            <li>PRIVATE - in this mode deployed classes do not share resources</li>\
-                            <li>ISOLATED - in this mode tasks or classes deployed within the same class loader will share the same instances of resources</li>\
-                            <li>SHARED - same as ISOLATED, but now tasks from different master nodes with the same user version and same class loader will share the same class loader on remote nodes</li>\
-                            <li>CONTINUOUS - same as SHARED deployment mode, but resources will not be undeployed even after all master nodes left grid</li>\
-                        </ul>')
-                .settings-row
-                    +checkbox('Enable peer class loading', model + '.peerClassLoadingEnabled', 'peerClassLoadingEnabled', 'Enables/disables peer class loading')
-                .settings-row
-                    +number('Missed resources cache size:', model + '.peerClassLoadingMissedResourcesCacheSize', 'peerClassLoadingMissedResourcesCacheSize', enabled, '100', '0',
-                        'If size greater than 0, missed resources will be cached and next resource request ignored<br/>\
-                        If size is 0, then request for the resource will be sent to the remote node every time this resource is requested')
-                .settings-row
-                    +number('Pool size:', model + '.peerClassLoadingThreadPoolSize', 'peerClassLoadingThreadPoolSize', enabled, '2', '1', 'Thread pool size to use for peer class loading')
-                .settings-row
-                    ignite-form-group(ng-model=exclude ng-form=form)
-                        ignite-form-field-label
-                            | Local class path exclude
-                        ignite-form-group-tooltip
-                            | List of packages from the system classpath that need to be peer-to-peer loaded from task originating node<br/>
-                            | '*' is supported at the end of the package name which means that all sub-packages and their classes are included like in Java package import clause
-                        ignite-form-group-add(ng-show='#{enabled}' ng-click='(group.add = [{}])')
-                            | Add package name.
-
-                        -var uniqueTip = 'Such package already exists'
-                        -var tipJavaPackageName = 'Package name is invalid'
-                        -var tipJavaKeyWord = 'Package name could not contains reserved java keyword'
-
-                        .group-content(ng-if=exclude + '.length')
-                            -var field = 'edit'
-                            -var valid = 'form[ngModelName].$valid'
-                            -var unique = 'form[ngModelName].$error.igniteUnique'
-                            -var javaPackageName = 'form[ngModelName].$error.javaPackageName'
-                            -var javaKeywords = 'form[ngModelName].$error.javaKeywords'
-                            -var save = exclude + '[$index] = ' + field
-
-                            div(ng-show=enabled)
-                                ignite-form-field(ng-repeat='model in #{exclude} track by $index' type='internal' name='Package name')
-                                    .indexField
-                                        | {{ $index+1 }})
-                                    +table-remove-button(exclude, 'Remove package name')
-                                    span(ng-hide='field.edit')
-                                        a.labelFormField(ng-click='#{enabled} && (field.edit = true)') {{ model }}
-                                    span(ng-if='field.edit' ng-init='#{field} = model')
-                                        +table-java-package-field(field, exclude, valid, save, false)
-                                            +table-save-button(valid, save, false)
-                                            +unique-feedback(unique, uniqueTip)
-                                            +error-feedback(javaPackageName, 'javaPackageName', tipJavaPackageName)
-                                            +error-feedback(javaKeywords, 'javaKeywords', tipJavaKeyWord)
-                            div(ng-hide=enabled)
-                                ignite-form-field(ng-repeat='model in #{exclude} track by $index' type='internal' name='Package name')
-                                    .labelFormField.labelField
-                                        | {{ $index+1 }})
-                                    span.labelFormField
-                                        | {{ model }}
-
-                        .group-content(ng-repeat='field in group.add')
-                            -var field = 'new'
-                            -var valid = 'form[ngModelName].$valid'
-                            -var unique = 'form[ngModelName].$error.igniteUnique'
-                            -var javaPackageName = 'form[ngModelName].$error.javaPackageName'
-                            -var javaKeywords = 'form[ngModelName].$error.javaKeywords'
-                            -var save = exclude + '.push(' + field + ')'
-
-                            ignite-form-field(type='internal' name='Package name')
-                                +table-java-package-field(field, exclude, valid, save, true)
-                                    +table-save-button(valid, save, true)
-                                    +unique-feedback(unique, uniqueTip)
-                                    +error-feedback(javaPackageName, 'javaPackageName', tipJavaPackageName)
-                                    +error-feedback(javaKeywords, 'javaKeywords', tipJavaKeyWord)
-
-
-                        .group-content-empty(ng-if='!(#{exclude}.length) && !group.add.length')
-                            | Not defined
-            .col-sm-6
-                +preview-xml-java(model, 'clusterDeployment')

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/src/main/js/app/modules/states/configuration/clusters/discovery.directive.js
----------------------------------------------------------------------
diff --git a/modules/web-console/src/main/js/app/modules/states/configuration/clusters/discovery.directive.js b/modules/web-console/src/main/js/app/modules/states/configuration/clusters/discovery.directive.js
deleted file mode 100644
index 80286ac..0000000
--- a/modules/web-console/src/main/js/app/modules/states/configuration/clusters/discovery.directive.js
+++ /dev/null
@@ -1,27 +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 templateUrl from './discovery.jade';
-
-export default ['igniteConfigurationClustersDiscovery', [() => {
-    return {
-        scope: true,
-        restrict: 'E',
-        templateUrl,
-        replace: true
-    };
-}]];

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/src/main/js/app/modules/states/configuration/clusters/discovery.jade
----------------------------------------------------------------------
diff --git a/modules/web-console/src/main/js/app/modules/states/configuration/clusters/discovery.jade b/modules/web-console/src/main/js/app/modules/states/configuration/clusters/discovery.jade
deleted file mode 100644
index 15b7065..0000000
--- a/modules/web-console/src/main/js/app/modules/states/configuration/clusters/discovery.jade
+++ /dev/null
@@ -1,83 +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.
-
-include ../../../../../app/helpers/jade/mixins.jade
-
--var form = 'discovery'
--var model = 'backupItem.discovery'
-
-form.panel.panel-default(name=form novalidate)
-    .panel-heading(bs-collapse-toggle ng-click='ui.loadPanel("#{form}")')
-        ignite-form-panel-chevron
-        label Discovery
-        ignite-form-field-tooltip.tipLabel
-            | Discovery properties configuration
-        ignite-form-revert
-    .panel-collapse(role='tabpanel' bs-collapse-target id=form)
-        .panel-body(ng-if='ui.isPanelLoaded("#{form}")')
-            .col-sm-6
-                .settings-row
-                    +text-ip-address('Local address:', model + '.localAddress', 'discoLocalAddress', 'true', '228.1.2.4', 'Local address')
-                .settings-row
-                    +number-min-max('Local port:', model + '.localPort', 'discoLocalPort', 'true', '47500', '1024', '65535', 'Local port which node uses')
-                .settings-row
-                    +number('Local port range:', model + '.localPortRange', 'discoLocalPortRange', 'true', '100', '1', 'Local port range')
-                .settings-row
-                    +java-class('Address resolver:', model + '.addressResolver', 'discoAddressResolver', 'true', 'false',
-                        'Class name of resolution between external and internal addresses provider')
-                .settings-row
-                    +number('Socket timeout:', model + '.socketTimeout', 'socketTimeout', 'true', '5000', '0', 'Socket operations timeout')
-                .settings-row
-                    +number('Acknowledgement timeout:', model + '.ackTimeout', 'ackTimeout', 'true', '5000', '0', 'Message acknowledgement timeout')
-                .settings-row
-                    +number('Max acknowledgement timeout:', model + '.maxAckTimeout', 'maxAckTimeout', 'true', '600000', '0', 'Maximum message acknowledgement timeout')
-                .settings-row
-                    +number('Network timeout:', model + '.networkTimeout', 'discoNetworkTimeout', 'true', '5000', '1', 'Network timeout')
-                .settings-row
-                    +number('Join timeout:', model + '.joinTimeout', 'joinTimeout', 'true', '0', '0',
-                        'Join timeout<br/>' +
-                        '0 means wait forever')
-                .settings-row
-                    +number('Thread priority:', model + '.threadPriority', 'threadPriority', 'true', '10', '1', 'Thread priority for all threads started by SPI')
-                .settings-row
-                    +number('Heartbeat frequency:', model + '.heartbeatFrequency', 'heartbeatFrequency', 'true', '2000', '1', 'Heartbeat messages issuing frequency')
-                .settings-row
-                    +number('Max heartbeats miss w/o init:', model + '.maxMissedHeartbeats', 'maxMissedHeartbeats', 'true', '1', '1',
-                        'Max heartbeats count node can miss without initiating status check')
-                .settings-row
-                    +number('Max heartbeats miss w/o failing client node:', model + '.maxMissedClientHeartbeats', 'maxMissedClientHeartbeats', 'true', '5', '1')
-                .settings-row
-                    +number('Topology history:', model + '.topHistorySize', 'topHistorySize', 'true', '1000', '0', 'Size of topology snapshots history')
-                .settings-row
-                    +java-class('Discovery listener:', model + '.listener', 'discoListener', 'true', 'false', 'Grid discovery listener')
-                .settings-row
-                    +java-class('Data exchange:', model + '.dataExchange', 'dataExchange', 'true', 'false', 'Class name of handler for initial data exchange between Ignite nodes')
-                .settings-row
-                    +java-class('Metrics provider:', model + '.metricsProvider', 'metricsProvider', 'true', 'false', 'Class name of metric provider to discovery SPI')
-                .settings-row
-                    +number('Reconnect count:', model + '.reconnectCount', 'discoReconnectCount', 'true', '10', '1', 'Reconnect attempts count')
-                .settings-row
-                    +number('Statistics frequency:', model + '.statisticsPrintFrequency', 'statisticsPrintFrequency', 'true', '0', '1', 'Statistics print frequency')
-                .settings-row
-                    +number('IP finder clean frequency:', model + '.ipFinderCleanFrequency', 'ipFinderCleanFrequency', 'true', '60000', '1', 'IP finder clean frequency')
-                .settings-row
-                    +java-class('Node authenticator:', model + '.authenticator', 'authenticator', 'true', 'false', 'Node authenticator')
-                .settings-row
-                    +checkbox('Force server mode', model + '.forceServerMode', 'forceServerMode', 'Force server mode')
-                .settings-row
-                    +checkbox('Client reconnect disabled', model + '.clientReconnectDisabled', 'clientReconnectDisabled', 'Client reconnect disabled')
-            .col-sm-6
-                +preview-xml-java(model, 'clusterDiscovery')

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/src/main/js/app/modules/states/configuration/clusters/events.directive.js
----------------------------------------------------------------------
diff --git a/modules/web-console/src/main/js/app/modules/states/configuration/clusters/events.directive.js b/modules/web-console/src/main/js/app/modules/states/configuration/clusters/events.directive.js
deleted file mode 100644
index ee25ae2..0000000
--- a/modules/web-console/src/main/js/app/modules/states/configuration/clusters/events.directive.js
+++ /dev/null
@@ -1,27 +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 templateUrl from './events.jade';
-
-export default ['igniteConfigurationClustersEvents', [() => {
-    return {
-        scope: true,
-        restrict: 'E',
-        templateUrl,
-        replace: true
-    };
-}]];

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/src/main/js/app/modules/states/configuration/clusters/events.jade
----------------------------------------------------------------------
diff --git a/modules/web-console/src/main/js/app/modules/states/configuration/clusters/events.jade b/modules/web-console/src/main/js/app/modules/states/configuration/clusters/events.jade
deleted file mode 100644
index 42582ac..0000000
--- a/modules/web-console/src/main/js/app/modules/states/configuration/clusters/events.jade
+++ /dev/null
@@ -1,37 +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.
-
-include ../../../../../app/helpers/jade/mixins.jade
-
--var form = 'events'
--var model = 'backupItem'
-
-form.panel.panel-default(name=form novalidate)
-    .panel-heading(bs-collapse-toggle ng-click='ui.loadPanel("#{form}")')
-        ignite-form-panel-chevron
-        label Events
-        ignite-form-field-tooltip.tipLabel
-            | Grid events are used for notification about what happens within the grid
-        ignite-form-revert
-    .panel-collapse(role='tabpanel' bs-collapse-target id=form)
-        .panel-body(ng-if='ui.isPanelLoaded("#{form}")')
-            .col-sm-6
-                .settings-row
-                    +dropdown-multiple('Include type:', model + '.includeEventTypes', 'includeEventTypes', 'true', 'Choose recorded event types', '', 'eventGroups',
-                        'Array of event types, which will be recorded by GridEventStorageManager#record(Event)<br/>\
-                        Note, that either the include event types or the exclude event types can be established')
-            .col-sm-6
-                +preview-xml-java(model, 'clusterEvents')

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/src/main/js/app/modules/states/configuration/clusters/failover.directive.js
----------------------------------------------------------------------
diff --git a/modules/web-console/src/main/js/app/modules/states/configuration/clusters/failover.directive.js b/modules/web-console/src/main/js/app/modules/states/configuration/clusters/failover.directive.js
deleted file mode 100644
index b9f59ba..0000000
--- a/modules/web-console/src/main/js/app/modules/states/configuration/clusters/failover.directive.js
+++ /dev/null
@@ -1,27 +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 templateUrl from './failover.jade';
-
-export default ['igniteConfigurationClustersFailover', [() => {
-    return {
-        scope: true,
-        restrict: 'E',
-        templateUrl,
-        replace: true
-    };
-}]];

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/src/main/js/app/modules/states/configuration/clusters/failover.jade
----------------------------------------------------------------------
diff --git a/modules/web-console/src/main/js/app/modules/states/configuration/clusters/failover.jade b/modules/web-console/src/main/js/app/modules/states/configuration/clusters/failover.jade
deleted file mode 100644
index a973aeb..0000000
--- a/modules/web-console/src/main/js/app/modules/states/configuration/clusters/failover.jade
+++ /dev/null
@@ -1,82 +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.
-
-include ../../../../../app/helpers/jade/mixins.jade
-
--var model = 'backupItem'
--var form = 'failoverSpi'
--var failoverSpi = model + '.failoverSpi'
--var failoverCustom = 'failover.kind === "Custom"'
-
-form.panel.panel-default(name=form novalidate)
-    .panel-heading(bs-collapse-toggle ng-click='ui.loadPanel("#{form}")')
-        ignite-form-panel-chevron
-        label Failover configuration
-        ignite-form-field-tooltip.tipLabel
-            | Failover SPI provides ability to supply custom logic for handling failed execution of a grid job
-        ignite-form-revert
-    .panel-collapse(role='tabpanel' bs-collapse-target id=form)
-        .panel-body(ng-if='ui.isPanelLoaded("#{form}")')
-            .col-sm-6
-                .settings-row(ng-init='failoverSpiTbl={type: "failoverSpi", model: "failoverSpi", focusId: "kind", ui: "failover-table"}')
-                    ignite-form-group(ng-model='#{failoverSpi}' ng-form=form)
-                        ignite-form-field-label
-                            | Failover SPI configurations
-                        ignite-form-group-tooltip
-                            | Failover SPI configurations
-                        ignite-form-group-add(ng-click='tableNewItem(failoverSpiTbl)')
-                            | Add failover SPI
-                        .group-content-empty(ng-if='!(#{failoverSpi} && #{failoverSpi}.length > 0)')
-                            | Not defined
-                        .group-content(ng-show='#{failoverSpi} && #{failoverSpi}.length > 0' ng-repeat='failover in #{failoverSpi} track by $index')
-                            hr(ng-if='$index != 0')
-                            .settings-row
-                                ignite-form-field
-                                    ignite-form-field-label
-                                        | Failover SPI
-                                    i.tipField.fa.fa-remove(bs-tooltip='"Remove Failover SPI"' ng-click='removeFailoverConfiguration($index)')
-                                    ignite-form-field-tooltip
-                                        | Provides ability to supply custom logic for handling failed execution of a grid job
-                                        ul
-                                            li Job stealing - Supports job stealing from over-utilized nodes to under-utilized nodes
-                                            li Never - Jobs are ordered as they arrived
-                                            li Always - Jobs are first ordered by their priority
-                                            li Custom - Jobs are activated immediately on arrival to mapped node
-                                            li Default - Default FailoverSpi implementation
-                                    ignite-form-field-dropdown(
-                                        data-id='failoverKind{{$index}}'
-                                        data-name='failoverKind{{$index}}'
-                                        data-options='[\
-                                            {value: "JobStealing", label: "Job stealing"},\
-                                            {value: "Never", label: "Never"},\
-                                            {value: "Always", label: "Always"},\
-                                            {value: "Custom", label: "Custom"}\
-                                        ]'
-                                        data-ng-model='failover.kind'
-                                        data-ng-required='true'
-                                        data-placeholder='Choose Failover SPI'
-                                    )
-                            .settings-row(ng-show='failover.kind === "JobStealing"')
-                                +number('Maximum failover attempts:', 'failover.JobStealing.maximumFailoverAttempts', 'jsMaximumFailoverAttempts{{$index}}', 'true', '5', '0',
-                                    'Maximum number of attempts to execute a failed job on another node')
-                            .settings-row(ng-show='failover.kind === "Always"')
-                                +number('Maximum failover attempts:', 'failover.Always.maximumFailoverAttempts', 'alwaysMaximumFailoverAttempts{{$index}}', 'true', '5', '0',
-                                    'Maximum number of attempts to execute a failed job on another node')
-                            .settings-row(ng-show=failoverCustom)
-                                +java-class('SPI implementation', 'failover.Custom.class', 'failoverSpiClass{{$index}}', 'true', failoverCustom,
-                                    'Custom FailoverSpi implementation class name.')
-            .col-sm-6
-                +preview-xml-java(model, 'clusterFailover')

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/src/main/js/app/modules/states/configuration/clusters/general.directive.js
----------------------------------------------------------------------
diff --git a/modules/web-console/src/main/js/app/modules/states/configuration/clusters/general.directive.js b/modules/web-console/src/main/js/app/modules/states/configuration/clusters/general.directive.js
deleted file mode 100644
index ccfadbe..0000000
--- a/modules/web-console/src/main/js/app/modules/states/configuration/clusters/general.directive.js
+++ /dev/null
@@ -1,27 +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 templateUrl from './general.jade';
-
-export default ['igniteConfigurationClustersGeneral', [() => {
-    return {
-        scope: true,
-        restrict: 'E',
-        templateUrl,
-        replace: true
-    };
-}]];

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/src/main/js/app/modules/states/configuration/clusters/general.jade
----------------------------------------------------------------------
diff --git a/modules/web-console/src/main/js/app/modules/states/configuration/clusters/general.jade b/modules/web-console/src/main/js/app/modules/states/configuration/clusters/general.jade
deleted file mode 100644
index 2ed0db0..0000000
--- a/modules/web-console/src/main/js/app/modules/states/configuration/clusters/general.jade
+++ /dev/null
@@ -1,68 +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.
-
-include ../../../../../app/helpers/jade/mixins.jade
-
--var form = 'general'
--var model = 'backupItem'
-
-form.panel.panel-default(name=form novalidate)
-    .panel-heading(bs-collapse-toggle)
-        ignite-form-panel-chevron
-        label General
-        ignite-form-revert
-    .panel-collapse(role='tabpanel' bs-collapse-target id=form)
-        .panel-body
-            .col-sm-6
-                .settings-row
-                    +text('Name:', model + '.name', 'clusterName', 'true', 'Input name', 'Grid name')
-                .settings-row
-                    +caches(model, 'Select caches to start in cluster or add a new cache')
-                .settings-row
-                    +text-ip-address('Local host:', model + '.localHost', 'localHost', 'true', '0.0.0.0', 'System-wide local address or host for all Ignite components to bind to')
-                .settings-row
-                    +dropdown('Discovery:', model + '.discovery.kind', 'discovery', 'true', 'Choose discovery', 'discoveries',
-                        'Discovery allows to discover remote nodes in grid\
-                        <ul>\
-                            <li>Static IPs - IP Finder which works only with pre configured list of IP addresses specified</li>\
-                            <li>Multicast - Multicast based IP finder</li>\
-                            <li>AWS S3 - AWS S3 based IP finder</li>\
-                            <li>Apache jclouds - Apache jclouds multi cloud toolkit based IP finder</li>\
-                            <li>Google cloud storage - Google Cloud Storage based IP finder</li>\
-                            <li>JDBC - JDBC based IP finder</li>\
-                            <li>Shared filesystem - Shared filesystem based IP finder</li>\
-                            <li>Apache ZooKeeper - Apache ZooKeeper based IP finder</li>\
-                        </ul>')
-                .settings-row
-                    .panel-details
-                        ignite-configuration-clusters-general-discovery-cloud(
-                            ng-show='#{model}.discovery.kind === "Cloud"')
-                        ignite-configuration-clusters-general-discovery-google(
-                            ng-show='#{model}.discovery.kind === "GoogleStorage"')
-                        ignite-configuration-clusters-general-discovery-jdbc(
-                            ng-show='#{model}.discovery.kind === "Jdbc"')
-                        ignite-configuration-clusters-general-discovery-multicast(
-                            ng-show='#{model}.discovery.kind === "Multicast"')
-                        ignite-configuration-clusters-general-discovery-s3(
-                            ng-show='#{model}.discovery.kind === "S3"')
-                        ignite-configuration-clusters-general-discovery-shared(
-                            ng-show='#{model}.discovery.kind === "SharedFs"')
-                        ignite-configuration-clusters-general-discovery-vm(
-                            ng-show='#{model}.discovery.kind === "Vm"')
-                        ignite-configuration-clusters-general-discovery-zookeeper(
-                            ng-show='#{model}.discovery.kind === "ZooKeeper"')
-            .col-sm-6
-                +preview-xml-java(model, 'clusterCaches', 'caches')

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/src/main/js/app/modules/states/configuration/clusters/general/discovery/cloud.directive.js
----------------------------------------------------------------------
diff --git a/modules/web-console/src/main/js/app/modules/states/configuration/clusters/general/discovery/cloud.directive.js b/modules/web-console/src/main/js/app/modules/states/configuration/clusters/general/discovery/cloud.directive.js
deleted file mode 100644
index 8fa7edc..0000000
--- a/modules/web-console/src/main/js/app/modules/states/configuration/clusters/general/discovery/cloud.directive.js
+++ /dev/null
@@ -1,27 +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 templateUrl from './cloud.jade';
-
-export default ['igniteConfigurationClustersGeneralDiscoveryCloud', [() => {
-    return {
-        scope: true,
-        restrict: 'E',
-        templateUrl,
-        replace: true
-    };
-}]];

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/src/main/js/app/modules/states/configuration/clusters/general/discovery/cloud.jade
----------------------------------------------------------------------
diff --git a/modules/web-console/src/main/js/app/modules/states/configuration/clusters/general/discovery/cloud.jade b/modules/web-console/src/main/js/app/modules/states/configuration/clusters/general/discovery/cloud.jade
deleted file mode 100644
index 3a6565d..0000000
--- a/modules/web-console/src/main/js/app/modules/states/configuration/clusters/general/discovery/cloud.jade
+++ /dev/null
@@ -1,127 +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.
-
-include ../../../../../../../app/helpers/jade/mixins.jade
-
--var discoveryKind = 'Cloud'
--var required = 'backupItem.discovery.kind == "' + discoveryKind + '"'
--var model = 'backupItem.discovery.Cloud'
--var regions = model + '.regions'
--var zones = model + '.zones'
--var formRegions = 'discoveryCloudRegions'
--var formZones = 'discoveryCloudZones'
-
-div
-    .details-row
-        +text('Credential:', model + '.credential', 'credential', 'false', 'Input cloud credential',
-            'Credential that is used during authentication on the cloud<br/>\
-            Depending on a cloud platform it can be a password or access key')
-    .details-row
-        +text('Path to credential:', model + '.credentialPath', 'credentialPath', 'false', 'Input pathto credential',
-            'Path to a credential that is used during authentication on the cloud<br/>\
-            Access key or private key should be stored in a plain or PEM file without a passphrase')
-    .details-row
-        +text('Identity:', model + '.identity', discoveryKind + 'Identity', required, 'Input identity',
-            'Identity that is used as a user name during a connection to the cloud<br/>\
-            Depending on a cloud platform it can be an email address, user name, etc')
-    .details-row
-        +text('Provider:', model + '.provider', discoveryKind + 'Provider', required, 'Input provider', 'Cloud provider to use')
-    .details-row
-        ignite-form-group(ng-model=regions ng-form=formRegions)
-            -var uniqueTip = 'Such region already exists!'
-
-            ignite-form-field-label
-                | Regions
-            ignite-form-group-tooltip
-                | List of regions where VMs are located#[br]
-                | If the regions are not set then every region, that a cloud provider has, will be investigated. This could lead to significant performance degradation#[br]
-                | Note, that some cloud providers, like Google Compute Engine, doesn't have a notion of a region. For such providers regions are redundant
-            ignite-form-group-add(ng-click='group.add = [{}]')
-                | Add new region
-
-            .group-content(ng-if='#{regions}.length')
-                -var field = 'edit'
-                -var valid = 'form[ngModelName].$valid'
-                -var unique = 'form[ngModelName].$error.igniteUnique'
-                -var save = regions + '[$index] = ' + field
-
-                ignite-form-field(ng-repeat='model in #{regions} track by $index' type='internal' name='Region')
-                    .indexField
-                        | {{ $index+1 }})
-                    +table-remove-button(regions, 'Remove region')
-                    span(ng-hide='field.edit')
-                        a.labelFormField(ng-click='field.edit = true') {{ model }}
-                    span(ng-if='field.edit' ng-init='#{field} = model')
-                        +table-text-field(field, regions, valid, save, 'Region name', false)
-                            +table-save-button(valid, save, false)
-                            +unique-feedback(unique, uniqueTip)
-
-            .group-content(ng-repeat='field in group.add')
-                -var field = 'new'
-                -var valid = 'form[ngModelName].$valid'
-                -var unique = 'form[ngModelName].$error.igniteUnique'
-                -var save = regions + '.push(' + field + ')'
-
-                ignite-form-field(type='internal' name='Region')
-                    +table-text-field(field, regions, valid, save, 'Region name', true)
-                        +table-save-button(valid, save, true)
-                        +unique-feedback(unique, uniqueTip)
-
-            .group-content-empty(ng-if='!(#{regions}.length) && !group.add.length')
-                | Not defined
-    .details-row
-        ignite-form-group(ng-model=zones ng-form=formZones)
-            -var uniqueTip = 'Such zone already exists!'
-
-            ignite-form-field-label
-                | Zones
-            ignite-form-group-tooltip
-                | List of zones where VMs are located#[br]
-                | If the zones are not set then every zone from specified regions, will be taken into account#[br]
-                | Note, that some cloud providers, like Rackspace, doesn't have a notion of a zone. For such providers zones are redundant
-            ignite-form-group-add(ng-click='group.add = [{}]')
-                | Add new zone
-
-            .group-content(ng-if='#{zones}.length')
-                -var field = 'edit'
-                -var valid = 'form[ngModelName].$valid'
-                -var unique = 'form[ngModelName].$error.igniteUnique'
-                -var save = zones + '[$index] = ' + field
-
-                ignite-form-field(ng-repeat='model in #{zones} track by $index' type='internal' name='Zone')
-                    .indexField
-                        | {{ $index+1 }})
-                    +table-remove-button(zones, 'Remove zone')
-                    span(ng-hide='field.edit')
-                        a.labelFormField(ng-click='field.edit = true') {{ model }}
-                    span(ng-if='field.edit' ng-init='#{field} = model')
-                        +table-text-field(field, zones, valid, save, 'Zone name', false)
-                            +table-save-button(valid, save, false)
-                            +unique-feedback(unique, uniqueTip)
-
-            .group-content(ng-repeat='field in group.add')
-                -var field = 'new'
-                -var valid = 'form[ngModelName].$valid'
-                -var unique = 'form[ngModelName].$error.igniteUnique'
-                -var save = zones + '.push(' + field + ')'
-
-                ignite-form-field(type='internal' name='Zone')
-                    +table-text-field(field, zones, valid, save, 'Zone name', true)
-                        +table-save-button(valid, save, true)
-                        +unique-feedback(unique, uniqueTip)
-
-            .group-content-empty(ng-if='!(#{zones}.length) && !group.add.length')
-                | Not defined

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/src/main/js/app/modules/states/configuration/clusters/general/discovery/google.directive.js
----------------------------------------------------------------------
diff --git a/modules/web-console/src/main/js/app/modules/states/configuration/clusters/general/discovery/google.directive.js b/modules/web-console/src/main/js/app/modules/states/configuration/clusters/general/discovery/google.directive.js
deleted file mode 100644
index a409946..0000000
--- a/modules/web-console/src/main/js/app/modules/states/configuration/clusters/general/discovery/google.directive.js
+++ /dev/null
@@ -1,27 +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 templateUrl from './google.jade';
-
-export default ['igniteConfigurationClustersGeneralDiscoveryGoogle', [() => {
-    return {
-        scope: true,
-        restrict: 'E',
-        templateUrl,
-        replace: true
-    };
-}]];

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/src/main/js/app/modules/states/configuration/clusters/general/discovery/google.jade
----------------------------------------------------------------------
diff --git a/modules/web-console/src/main/js/app/modules/states/configuration/clusters/general/discovery/google.jade b/modules/web-console/src/main/js/app/modules/states/configuration/clusters/general/discovery/google.jade
deleted file mode 100644
index 2a651df..0000000
--- a/modules/web-console/src/main/js/app/modules/states/configuration/clusters/general/discovery/google.jade
+++ /dev/null
@@ -1,38 +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.
-
-include ../../../../../../../app/helpers/jade/mixins.jade
-
-
--var discoveryKind = 'GoogleStorage'
--var required = 'backupItem.discovery.kind == "' + discoveryKind + '"'
--var model = 'backupItem.discovery.GoogleStorage'
-
-div
-    .details-row
-        +text('Project name:', model + '.projectName', discoveryKind + 'ProjectName', required, 'Input project name', '' +
-            'Google Cloud Platforms project name<br/>\
-            Usually this is an auto generated project number(ex. 208709979073) that can be found in "Overview" section of Google Developer Console')
-    .details-row
-        +text('Bucket name:', model + '.bucketName', discoveryKind + 'BucketName', required, 'Input bucket name',
-            'Google Cloud Storage bucket name<br/>\
-            If the bucket does not exist Ignite will automatically create it<br/>\
-            However the name must be unique across whole Google Cloud Storage and Service Account Id must be authorized to perform this operation')
-    .details-row
-        +text('Private key path:', model + '.serviceAccountP12FilePath', discoveryKind + 'ServiceAccountP12FilePath', required, 'Input private key path',
-            'Full path to the private key in PKCS12 format of the Service Account')
-    .details-row
-        +text('Account id:', model + '.serviceAccountId', discoveryKind + 'ServiceAccountId', required, 'Input account id', 'Service account ID (typically an e-mail address)')

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/src/main/js/app/modules/states/configuration/clusters/general/discovery/jdbc.directive.js
----------------------------------------------------------------------
diff --git a/modules/web-console/src/main/js/app/modules/states/configuration/clusters/general/discovery/jdbc.directive.js b/modules/web-console/src/main/js/app/modules/states/configuration/clusters/general/discovery/jdbc.directive.js
deleted file mode 100644
index 6edd6ed..0000000
--- a/modules/web-console/src/main/js/app/modules/states/configuration/clusters/general/discovery/jdbc.directive.js
+++ /dev/null
@@ -1,27 +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 templateUrl from './jdbc.jade';
-
-export default ['igniteConfigurationClustersGeneralDiscoveryJdbc', [() => {
-    return {
-        scope: true,
-        restrict: 'E',
-        templateUrl,
-        replace: true
-    };
-}]];

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/src/main/js/app/modules/states/configuration/clusters/general/discovery/jdbc.jade
----------------------------------------------------------------------
diff --git a/modules/web-console/src/main/js/app/modules/states/configuration/clusters/general/discovery/jdbc.jade b/modules/web-console/src/main/js/app/modules/states/configuration/clusters/general/discovery/jdbc.jade
deleted file mode 100644
index fbca508..0000000
--- a/modules/web-console/src/main/js/app/modules/states/configuration/clusters/general/discovery/jdbc.jade
+++ /dev/null
@@ -1,24 +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.
-
-include ../../../../../../../app/helpers/jade/mixins.jade
-
--var model = 'backupItem.discovery.Jdbc'
-
-div
-    .details-row
-        +checkbox('DB schema should be initialized by Ignite', model + '.initSchema', 'initSchema',
-            'Flag indicating whether DB schema should be initialized by Ignite or was explicitly created by user')

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/src/main/js/app/modules/states/configuration/clusters/general/discovery/multicast.directive.js
----------------------------------------------------------------------
diff --git a/modules/web-console/src/main/js/app/modules/states/configuration/clusters/general/discovery/multicast.directive.js b/modules/web-console/src/main/js/app/modules/states/configuration/clusters/general/discovery/multicast.directive.js
deleted file mode 100644
index 67775d2..0000000
--- a/modules/web-console/src/main/js/app/modules/states/configuration/clusters/general/discovery/multicast.directive.js
+++ /dev/null
@@ -1,27 +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 templateUrl from './multicast.jade';
-
-export default ['igniteConfigurationClustersGeneralDiscoveryMulticast', [() => {
-    return {
-        scope: true,
-        restrict: 'E',
-        templateUrl,
-        replace: true
-    };
-}]];

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/src/main/js/app/modules/states/configuration/clusters/general/discovery/multicast.jade
----------------------------------------------------------------------
diff --git a/modules/web-console/src/main/js/app/modules/states/configuration/clusters/general/discovery/multicast.jade b/modules/web-console/src/main/js/app/modules/states/configuration/clusters/general/discovery/multicast.jade
deleted file mode 100644
index 2c9dd50..0000000
--- a/modules/web-console/src/main/js/app/modules/states/configuration/clusters/general/discovery/multicast.jade
+++ /dev/null
@@ -1,109 +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.
-
-include ../../../../../../../app/helpers/jade/mixins.jade
-
--var form = 'general'
--var model = 'backupItem.discovery.Multicast'
--var addresses = model + '.addresses'
-
-div
-    .details-row
-        +text-ip-address('IP address:', model + '.multicastGroup', 'multicastGroup', 'true', '228.1.2.4', 'IP address of multicast group')
-    .details-row
-        +number-min-max('Port number:', model + '.multicastPort', 'multicastPort', 'true', '47400', '0', '65535', 'Port number which multicast messages are sent to')
-    .details-row
-        +number('Waits for reply:', model + '.responseWaitTime', 'responseWaitTime', 'true', '500', '0',
-            'Time in milliseconds IP finder waits for reply to multicast address request')
-    .details-row
-        +number('Attempts count:', model + '.addressRequestAttempts', 'addressRequestAttempts', 'true', '2', '0',
-            'Number of attempts to send multicast address request<br/>\
-            IP finder re - sends request only in case if no reply for previous request is received')
-    .details-row
-        +text-ip-address('Local address:', model + '.localAddress', 'localAddress', 'true', '0.0.0.0',
-            'Local host address used by this IP finder<br/>\
-            If provided address is non - loopback then multicast socket is bound to this interface<br/>\
-            If local address is not set or is any local address then IP finder creates multicast sockets for all found non - loopback addresses')
-    .details-row
-        -var form = 'discoveryMulticastAddresses';
-
-        ignite-form-group(ng-model=addresses ng-form=form)
-            -var uniqueTip = 'Such IP address already exists!'
-            -var ipAddressTip = 'Invalid IP address!'
-
-            ignite-form-field-label
-                | Addresses
-            ignite-form-group-tooltip
-                | Addresses may be represented as follows:#[br]
-                ul: li IP address (e.g. 127.0.0.1, 9.9.9.9, etc)
-                    li IP address and port (e.g. 127.0.0.1:47500, 9.9.9.9:47501, etc)
-                    li IP address and port range (e.g. 127.0.0.1:47500..47510, 9.9.9.9:47501..47504, etc)
-                    li Hostname (e.g. host1.com, host2, etc)
-                    li Hostname and port (e.g. host1.com:47500, host2:47502, etc)
-                    li Hostname and port range (e.g. host1.com:47500..47510, host2:47502..47508, etc)
-                | If port is 0 or not provided then default port will be used (depends on discovery SPI configuration)#[br]
-                | If port range is provided (e.g. host:port1..port2) the following should be considered:#[br]
-                ul: li port1 &lt; port2 should be true
-                    li Both port1 and port2 should be greater than 0
-            ignite-form-group-add(ng-click='group.add = [{}]')
-                | Add new address
-
-            .group-content(ng-if='#{addresses}.length')
-                -var field = 'edit'
-                -var valid = 'form[ngModelName].$valid'
-                -var unique = 'form[ngModelName].$error.igniteUnique'
-                -var ipaddress = 'form[ngModelName].$error.ipaddress'
-                -var ipaddressPort = 'form[ngModelName].$error.ipaddressPort'
-                -var ipaddressPortRange = 'form[ngModelName].$error.ipaddressPortRange'
-                -var save = addresses + '[$index] = ' + field
-
-                ignite-form-field(ng-repeat='model in #{addresses} track by $index' type='internal' name='Address')
-                    .indexField
-                        | {{ $index+1 }})
-                    +table-remove-button(addresses, 'Remove address')
-
-                    ignite-form-field-down(ng-if='!$last' ng-hide='field.edit' data-ng-model='model' data-models=addresses)
-                    ignite-form-field-up(ng-if='!$first' ng-hide='field.edit' data-ng-model='model' data-models=addresses)
-
-                    span(ng-hide='field.edit')
-                        a.labelFormField(ng-click='field.edit = true') {{ model }}
-                    span(ng-if='field.edit' ng-init='#{field} = model')
-                        +table-address-field(field, addresses, valid, save, false, true)
-                            +table-save-button(valid, save, false)
-                            +unique-feedback(unique, uniqueTip)
-                            +ipaddress-feedback(ipaddress)
-                            +ipaddress-port-feedback(ipaddressPort)
-                            +ipaddress-port-range-feedback(ipaddressPortRange)
-
-            .group-content(ng-repeat='field in group.add')
-                -var field = 'new'
-                -var valid = 'form[ngModelName].$valid'
-                -var unique = 'form[ngModelName].$error.igniteUnique'
-                -var ipaddress = 'form[ngModelName].$error.ipaddress'
-                -var ipaddressPort = 'form[ngModelName].$error.ipaddressPort'
-                -var ipaddressPortRange = 'form[ngModelName].$error.ipaddressPortRange'
-                -var save = addresses + '.push(' + field + ')'
-
-                ignite-form-field(type='internal' name='Address')
-                    +table-address-field(field, addresses, valid, save, true, true)
-                        +table-save-button(valid, save, true)
-                        +unique-feedback(unique, uniqueTip)
-                        +ipaddress-feedback(ipaddress)
-                        +ipaddress-port-feedback(ipaddressPort)
-                        +ipaddress-port-range-feedback(ipaddressPortRange)
-
-            .group-content-empty(ng-if='!(#{addresses}.length) && !group.add.length')
-                | Not defined

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/src/main/js/app/modules/states/configuration/clusters/general/discovery/s3.directive.js
----------------------------------------------------------------------
diff --git a/modules/web-console/src/main/js/app/modules/states/configuration/clusters/general/discovery/s3.directive.js b/modules/web-console/src/main/js/app/modules/states/configuration/clusters/general/discovery/s3.directive.js
deleted file mode 100644
index 25fd90a..0000000
--- a/modules/web-console/src/main/js/app/modules/states/configuration/clusters/general/discovery/s3.directive.js
+++ /dev/null
@@ -1,27 +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 templateUrl from './s3.jade';
-
-export default ['igniteConfigurationClustersGeneralDiscoveryS3', [() => {
-    return {
-        scope: true,
-        restrict: 'E',
-        templateUrl,
-        replace: true
-    };
-}]];

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/src/main/js/app/modules/states/configuration/clusters/general/discovery/s3.jade
----------------------------------------------------------------------
diff --git a/modules/web-console/src/main/js/app/modules/states/configuration/clusters/general/discovery/s3.jade b/modules/web-console/src/main/js/app/modules/states/configuration/clusters/general/discovery/s3.jade
deleted file mode 100644
index c2e29be..0000000
--- a/modules/web-console/src/main/js/app/modules/states/configuration/clusters/general/discovery/s3.jade
+++ /dev/null
@@ -1,27 +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.
-
-include ../../../../../../../app/helpers/jade/mixins.jade
-
--var discoveryKind = 'S3'
--var required = 'backupItem.discovery.kind == "' + discoveryKind + '"'
--var model = 'backupItem.discovery.S3'
-
-div
-    .details-row
-        +text('Bucket name:', model + '.bucketName', discoveryKind + 'BucketName', required, 'Input bucket name', 'Bucket name for IP finder')
-    .details-row
-        label Note, AWS credentials will be generated as stub

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/src/main/js/app/modules/states/configuration/clusters/general/discovery/shared.directive.js
----------------------------------------------------------------------
diff --git a/modules/web-console/src/main/js/app/modules/states/configuration/clusters/general/discovery/shared.directive.js b/modules/web-console/src/main/js/app/modules/states/configuration/clusters/general/discovery/shared.directive.js
deleted file mode 100644
index da1ee0c..0000000
--- a/modules/web-console/src/main/js/app/modules/states/configuration/clusters/general/discovery/shared.directive.js
+++ /dev/null
@@ -1,27 +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 templateUrl from './shared.jade';
-
-export default ['igniteConfigurationClustersGeneralDiscoveryShared', [() => {
-    return {
-        scope: true,
-        restrict: 'E',
-        templateUrl,
-        replace: true
-    };
-}]];

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/src/main/js/app/modules/states/configuration/clusters/general/discovery/shared.jade
----------------------------------------------------------------------
diff --git a/modules/web-console/src/main/js/app/modules/states/configuration/clusters/general/discovery/shared.jade b/modules/web-console/src/main/js/app/modules/states/configuration/clusters/general/discovery/shared.jade
deleted file mode 100644
index 5ae808a..0000000
--- a/modules/web-console/src/main/js/app/modules/states/configuration/clusters/general/discovery/shared.jade
+++ /dev/null
@@ -1,23 +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.
-
-include ../../../../../../../app/helpers/jade/mixins.jade
-
--var model = 'backupItem.discovery.SharedFs'
-
-div
-    .details-row
-        +text('File path:', model + '.path', 'path', 'false', 'disco/tcp', 'Shared path')

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/src/main/js/app/modules/states/configuration/clusters/general/discovery/vm.directive.js
----------------------------------------------------------------------
diff --git a/modules/web-console/src/main/js/app/modules/states/configuration/clusters/general/discovery/vm.directive.js b/modules/web-console/src/main/js/app/modules/states/configuration/clusters/general/discovery/vm.directive.js
deleted file mode 100644
index d07adc8..0000000
--- a/modules/web-console/src/main/js/app/modules/states/configuration/clusters/general/discovery/vm.directive.js
+++ /dev/null
@@ -1,27 +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 templateUrl from './vm.jade';
-
-export default ['igniteConfigurationClustersGeneralDiscoveryVm', [() => {
-    return {
-        scope: true,
-        restrict: 'E',
-        templateUrl,
-        replace: true
-    };
-}]];

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/src/main/js/app/modules/states/configuration/clusters/general/discovery/vm.jade
----------------------------------------------------------------------
diff --git a/modules/web-console/src/main/js/app/modules/states/configuration/clusters/general/discovery/vm.jade b/modules/web-console/src/main/js/app/modules/states/configuration/clusters/general/discovery/vm.jade
deleted file mode 100644
index 1f20613..0000000
--- a/modules/web-console/src/main/js/app/modules/states/configuration/clusters/general/discovery/vm.jade
+++ /dev/null
@@ -1,90 +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.
-
-include ../../../../../../../app/helpers/jade/mixins.jade
-
--var model = 'backupItem.discovery.Vm'
--var addresses = model + '.addresses'
--var form = 'discoveryVmAddresses'
-
-.details-row
-    ignite-form-group(ng-model=addresses ng-form=form)
-        -var uniqueTip = 'Such IP address already exists!'
-        -var ipAddressTip = 'Invalid IP address!'
-
-        ignite-form-field-label
-            | Addresses
-        ignite-form-group-tooltip
-            | Addresses may be represented as follows:
-            ul: li IP address (e.g. 127.0.0.1, 9.9.9.9, etc)
-                li IP address and port (e.g. 127.0.0.1:47500, 9.9.9.9:47501, etc)
-                li IP address and port range (e.g. 127.0.0.1:47500..47510, 9.9.9.9:47501..47504, etc)
-                li Hostname (e.g. host1.com, host2, etc)
-                li Hostname and port (e.g. host1.com:47500, host2:47502, etc)
-                li Hostname and port range (e.g. host1.com:47500..47510, host2:47502..47508, etc)
-            | If port is 0 or not provided then default port will be used (depends on discovery SPI configuration)#[br]
-            | If port range is provided (e.g. host:port1..port2) the following should be considered:
-            ul: li port1 &lt; port2 should be true
-                li Both port1 and port2 should be greater than 0
-        ignite-form-group-add(ng-click='group.add = [{}]')
-            | Add new address
-
-        .group-content(ng-if='#{addresses}.length')
-            -var field = 'edit'
-            -var valid = 'form[ngModelName].$valid'
-            -var unique = 'form[ngModelName].$error.igniteUnique'
-            -var ipaddress = 'form[ngModelName].$error.ipaddress'
-            -var ipaddressPort = 'form[ngModelName].$error.ipaddressPort'
-            -var ipaddressPortRange = 'form[ngModelName].$error.ipaddressPortRange'
-            -var save = addresses + '[$index] = ' + field
-
-            ignite-form-field(ng-repeat='model in #{addresses} track by $index' type='internal' name='Address')
-                .indexField
-                    | {{ $index+1 }})
-                +table-remove-button(addresses, 'Remove address')
-
-                ignite-form-field-down(ng-if='!$last' ng-hide='field.edit' data-ng-model='model' data-models=addresses)
-                ignite-form-field-up(ng-if='!$first' ng-hide='field.edit' data-ng-model='model' data-models=addresses)
-
-                span(ng-hide='field.edit')
-                    a.labelFormField(ng-click='field.edit = true') {{ model }}
-                span(ng-if='field.edit' ng-init='#{field} = model')
-                    +table-address-field(field, addresses, valid, save, false, true)
-                        +table-save-button(valid, save, false)
-                        +unique-feedback(unique, uniqueTip)
-                        +ipaddress-feedback(ipaddress)
-                        +ipaddress-port-feedback(ipaddressPort)
-                        +ipaddress-port-range-feedback(ipaddressPortRange)
-
-        .group-content(ng-repeat='field in group.add')
-            -var field = 'new'
-            -var valid = 'form[ngModelName].$valid'
-            -var unique = 'form[ngModelName].$error.igniteUnique'
-            -var ipaddress = 'form[ngModelName].$error.ipaddress'
-            -var ipaddressPort = 'form[ngModelName].$error.ipaddressPort'
-            -var ipaddressPortRange = 'form[ngModelName].$error.ipaddressPortRange'
-            -var save = addresses + '.push(' + field + ')'
-
-            ignite-form-field(type='internal' name='Address')
-                +table-address-field(field, addresses, valid, save, true, true)
-                    +table-save-button(valid, save, true)
-                    +unique-feedback(unique, uniqueTip)
-                    +ipaddress-feedback(ipaddress)
-                    +ipaddress-port-feedback(ipaddressPort)
-                    +ipaddress-port-range-feedback(ipaddressPortRange)
-
-        .group-content-empty(id='addresses' ng-if='!(#{addresses}.length) && !group.add.length')
-                | Not defined

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/src/main/js/app/modules/states/configuration/clusters/general/discovery/zookeeper.directive.js
----------------------------------------------------------------------
diff --git a/modules/web-console/src/main/js/app/modules/states/configuration/clusters/general/discovery/zookeeper.directive.js b/modules/web-console/src/main/js/app/modules/states/configuration/clusters/general/discovery/zookeeper.directive.js
deleted file mode 100644
index 3081443..0000000
--- a/modules/web-console/src/main/js/app/modules/states/configuration/clusters/general/discovery/zookeeper.directive.js
+++ /dev/null
@@ -1,27 +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 templateUrl from './zookeeper.jade';
-
-export default ['igniteConfigurationClustersGeneralDiscoveryZookeeper', [() => {
-    return {
-        scope: true,
-        restrict: 'E',
-        templateUrl,
-        replace: true
-    };
-}]];

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/src/main/js/app/modules/states/configuration/clusters/general/discovery/zookeeper.jade
----------------------------------------------------------------------
diff --git a/modules/web-console/src/main/js/app/modules/states/configuration/clusters/general/discovery/zookeeper.jade b/modules/web-console/src/main/js/app/modules/states/configuration/clusters/general/discovery/zookeeper.jade
deleted file mode 100644
index 72f0678..0000000
--- a/modules/web-console/src/main/js/app/modules/states/configuration/clusters/general/discovery/zookeeper.jade
+++ /dev/null
@@ -1,74 +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.
-
-include ../../../../../../../app/helpers/jade/mixins.jade
-
--var discoveryKind = 'ZooKeeper'
--var required = 'backupItem.discovery.kind == "' + discoveryKind + '"'
--var model = 'backupItem.discovery.ZooKeeper'
-
-div
-    .details-row
-        +java-class('Curator:', model + '.curator', 'curator', 'true', 'false',
-            'The Curator framework in use<br/>\
-            By default generates curator of org.apache.curator. framework.imps.CuratorFrameworkImpl\
-            class with configured connect string, retry policy, and default session and connection timeouts')
-    .details-row
-        +text('Connect string:', model + '.zkConnectionString', ZooKeeper + 'ConnectionString', required, 'host:port[chroot][,host:port[chroot]]',
-            'When "IGNITE_ZK_CONNECTION_STRING" system property is not configured this property will be used')
-    .details-row
-        +dropdown('Retry policy:', model + '.retryPolicy.kind', 'retryPolicy', 'true', 'Default',
-            '[\
-                {value: "ExponentialBackoff", label: "Exponential backoff"},\
-                {value: "BoundedExponentialBackoff", label: "Bounded exponential backoff"},\
-                {value: "UntilElapsed", label: "Until elapsed"},\
-                {value: "NTimes", label: "Max number of times"},\
-                {value: "OneTime", label: "Only once"},\
-                {value: "Forever", label: "Always allow retry"},\
-                {value: "Custom", label: "Custom"},\
-                {value: undefined, label: "Default"}\
-            ]',
-            'Available retry policies:\
-            <ul>\
-                <li>Exponential backoff - retries a set number of times with increasing sleep time between retries</li>\
-                <li>Bounded exponential backoff - retries a set number of times with an increasing (up to a maximum bound) sleep time between retries</li>\
-                <li>Until elapsed - retries until a given amount of time elapses</li>\
-                <li>Max number of times - retries a max number of times</li>\
-                <li>Only once - retries only once</li>\
-                <li>Always allow retry - retries infinitely</li>\
-                <li>Custom - custom retry policy implementation</li>\
-                <li>Default - exponential backoff retry policy with configured base sleep time equal to 1000ms and max retry count equal to 10</li>\
-            </ul>')
-    .details-row(ng-show='#{model}.retryPolicy.kind')
-        .panel-details
-            ignite-configuration-clusters-general-discovery-zookeeper-exponential(ng-show='#{model}.retryPolicy.kind === "ExponentialBackoff"')
-            ignite-configuration-clusters-general-discovery-zookeeper-bounded-exponential(ng-show='#{model}.retryPolicy.kind === "BoundedExponentialBackoff"')
-            ignite-configuration-clusters-general-discovery-zookeeper-until-elapsed(ng-show='#{model}.retryPolicy.kind === "UntilElapsed"')
-            ignite-configuration-clusters-general-discovery-zookeeper-n-times(ng-show='#{model}.retryPolicy.kind === "NTimes"')
-            ignite-configuration-clusters-general-discovery-zookeeper-one-time(ng-show='#{model}.retryPolicy.kind === "OneTime"')
-            ignite-configuration-clusters-general-discovery-zookeeper-forever(ng-show='#{model}.retryPolicy.kind === "Forever"')
-            ignite-configuration-clusters-general-discovery-zookeeper-custom(ng-show='#{model}.retryPolicy.kind === "Custom"')
-    .details-row
-        +text('Base path:', model + '.basePath', 'basePath', 'false', '/services', 'Base path for service registration')
-    .details-row
-        +text('Service name:', model + '.serviceName', 'serviceName', 'false', 'ignite',
-            'Service name to use, as defined by Curator&#39;s ServiceDiscovery recipe<br/>\
-            In physical ZooKeeper terms, it represents the node under basePath, under which services will be registered')
-    .details-row
-        +checkbox('Allow duplicate registrations', model + '.allowDuplicateRegistrations', 'allowDuplicateRegistrations',
-            'Whether to register each node only once, or if duplicate registrations are allowed<br/>\
-            Nodes will attempt to register themselves, plus those they know about<br/>\
-            By default, duplicate registrations are not allowed, but you might want to set this property to <b>true</b> if you have multiple network interfaces or if you are facing troubles')

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/src/main/js/app/modules/states/configuration/clusters/general/discovery/zookeeper/retrypolicy/bounded-exponential-backoff.directive.js
----------------------------------------------------------------------
diff --git a/modules/web-console/src/main/js/app/modules/states/configuration/clusters/general/discovery/zookeeper/retrypolicy/bounded-exponential-backoff.directive.js b/modules/web-console/src/main/js/app/modules/states/configuration/clusters/general/discovery/zookeeper/retrypolicy/bounded-exponential-backoff.directive.js
deleted file mode 100644
index 42fb229..0000000
--- a/modules/web-console/src/main/js/app/modules/states/configuration/clusters/general/discovery/zookeeper/retrypolicy/bounded-exponential-backoff.directive.js
+++ /dev/null
@@ -1,27 +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 templateUrl from './bounded-exponential-backoff.jade';
-
-export default ['igniteConfigurationClustersGeneralDiscoveryZookeeperBoundedExponential', [() => {
-    return {
-        scope: true,
-        restrict: 'E',
-        templateUrl,
-        replace: true
-    };
-}]];

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/src/main/js/app/modules/states/configuration/clusters/general/discovery/zookeeper/retrypolicy/bounded-exponential-backoff.jade
----------------------------------------------------------------------
diff --git a/modules/web-console/src/main/js/app/modules/states/configuration/clusters/general/discovery/zookeeper/retrypolicy/bounded-exponential-backoff.jade b/modules/web-console/src/main/js/app/modules/states/configuration/clusters/general/discovery/zookeeper/retrypolicy/bounded-exponential-backoff.jade
deleted file mode 100644
index 6f6e035..0000000
--- a/modules/web-console/src/main/js/app/modules/states/configuration/clusters/general/discovery/zookeeper/retrypolicy/bounded-exponential-backoff.jade
+++ /dev/null
@@ -1,27 +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.
-
-include ../../../../../../../../../app/helpers/jade/mixins.jade
-
--var model = 'backupItem.discovery.ZooKeeper.retryPolicy.BoundedExponentialBackoff'
-
-div
-    .details-row
-        +number('Base interval:', model + '.baseSleepTimeMs', 'beBaseSleepTimeMs', 'true', '1000', '0', 'Initial amount of time in ms to wait between retries')
-    .details-row
-        +number('Max interval:', model + '.maxSleepTimeMs', 'beMaxSleepTimeMs', 'true', 'Integer.MAX_VALUE', '0', 'Max time in ms to sleep on each retry')
-    .details-row
-        +number-min-max('Max retries:', model + '.maxRetries', 'beMaxRetries', 'true', '10', '0', '29', 'Max number of times to retry')

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/src/main/js/app/modules/states/configuration/clusters/general/discovery/zookeeper/retrypolicy/custom.directive.js
----------------------------------------------------------------------
diff --git a/modules/web-console/src/main/js/app/modules/states/configuration/clusters/general/discovery/zookeeper/retrypolicy/custom.directive.js b/modules/web-console/src/main/js/app/modules/states/configuration/clusters/general/discovery/zookeeper/retrypolicy/custom.directive.js
deleted file mode 100644
index 969356b..0000000
--- a/modules/web-console/src/main/js/app/modules/states/configuration/clusters/general/discovery/zookeeper/retrypolicy/custom.directive.js
+++ /dev/null
@@ -1,27 +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 templateUrl from './custom.jade';
-
-export default ['igniteConfigurationClustersGeneralDiscoveryZookeeperCustom', [() => {
-    return {
-        scope: true,
-        restrict: 'E',
-        templateUrl,
-        replace: true
-    };
-}]];


[33/52] ignite git commit: Web Console beta-3.

Posted by ak...@apache.org.
http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/frontend/app/modules/states/configuration/clusters/logger.jade
----------------------------------------------------------------------
diff --git a/modules/web-console/frontend/app/modules/states/configuration/clusters/logger.jade b/modules/web-console/frontend/app/modules/states/configuration/clusters/logger.jade
new file mode 100644
index 0000000..31f87a9
--- /dev/null
+++ b/modules/web-console/frontend/app/modules/states/configuration/clusters/logger.jade
@@ -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.
+
+include ../../../../../app/helpers/jade/mixins.jade
+
+-var form = 'logger'
+-var model = 'backupItem.logger'
+-var kind = model + '.kind'
+
+.panel.panel-default(ng-form=form novalidate)
+    .panel-heading(bs-collapse-toggle ng-click='ui.loadPanel("#{form}")')
+        ignite-form-panel-chevron
+        label Logger configuration
+        ignite-form-field-tooltip.tipLabel
+            | Logging functionality used throughout the system
+        ignite-form-revert
+    .panel-collapse(role='tabpanel' bs-collapse-target id=form)
+        .panel-body(ng-if='ui.isPanelLoaded("#{form}")')
+            .col-sm-6
+                .settings-row
+                    +dropdown('Logger:', kind, '"logger"', 'true', 'Default',
+                        '[\
+                            {value: "Log4j", label: "Apache Log4j"},\
+                            {value: "Log4j2", label: "Apache Log4j 2"},\
+                            {value: "SLF4J", label: "Simple Logging Facade (SLF4J)"},\
+                            {value: "Java", label: "Java logger (JUL)"},\
+                            {value: "JCL", label: "Jakarta Commons Logging (JCL)"},\
+                            {value: "Null", label: "Null logger"},\
+                            {value: "Custom", label: "Custom"},\
+                            {value: undefined, label: "Default"}\
+                        ]',
+                        'Logger implementations\
+                        <ul>\
+                            <li>Apache Log4j - log4j-based logger</li>\
+                            <li>Apache Log4j 2 - Log4j2-based logger</li>\
+                            <li>Simple Logging Facade (SLF4J) - SLF4j-based logger</li>\
+                            <li>Java logger (JUL) - built in java logger</li>\
+                            <li>Jakarta Commons Logging (JCL) - wraps any JCL (Jakarta Commons Logging) loggers</li>\
+                            <li>Null logger - logger which does not output anything</li>\
+                            <li>Custom - custom logger implementation</li>\
+                            <li>Default - Apache Log4j if awailable on classpath or Java logger otherwise</li>\
+                        </ul>')
+                .settings-row(ng-show='#{kind} && (#{kind} === "Log4j2" || #{kind} === "Log4j" || #{kind} === "Custom")')
+                    .panel-details
+                        div(ng-show='#{kind} === "Log4j2"')
+                            include ./logger/log4j2.jade
+                        div(ng-show='#{kind} === "Log4j"')
+                            include ./logger/log4j.jade
+                        div(ng-show='#{kind} === "Custom"')
+                            include ./logger/custom.jade
+            .col-sm-6
+                -var model = 'backupItem.logger'
+                +preview-xml-java(model, 'clusterLogger')

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/frontend/app/modules/states/configuration/clusters/logger/custom.jade
----------------------------------------------------------------------
diff --git a/modules/web-console/frontend/app/modules/states/configuration/clusters/logger/custom.jade b/modules/web-console/frontend/app/modules/states/configuration/clusters/logger/custom.jade
new file mode 100644
index 0000000..df80af0
--- /dev/null
+++ b/modules/web-console/frontend/app/modules/states/configuration/clusters/logger/custom.jade
@@ -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.
+
+include ../../../../../../app/helpers/jade/mixins.jade
+
+-var form = 'logger'
+-var model = 'backupItem.logger.Custom'
+-var required = 'backupItem.logger.kind === "Custom"'
+
+div
+    .details-row
+        +java-class('Class:', model + '.class', '"customLogger"', 'true', required, 'Logger implementation class name')

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/frontend/app/modules/states/configuration/clusters/logger/log4j.jade
----------------------------------------------------------------------
diff --git a/modules/web-console/frontend/app/modules/states/configuration/clusters/logger/log4j.jade b/modules/web-console/frontend/app/modules/states/configuration/clusters/logger/log4j.jade
new file mode 100644
index 0000000..cf556ec
--- /dev/null
+++ b/modules/web-console/frontend/app/modules/states/configuration/clusters/logger/log4j.jade
@@ -0,0 +1,50 @@
+//-
+    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.jade
+
+-var form = 'logger'
+-var model = 'backupItem.logger.Log4j'
+-var pathRequired = model + '.mode === "Path" && backupItem.logger.kind === "Log4j"'
+
+div
+    .details-row
+        +dropdown('Level:', model + '.level', '"log4jLevel"', 'true', 'Default',
+            '[\
+                {value: "OFF", label: "OFF"},\
+                {value: "FATAL", label: "FATAL"},\
+                {value: "ERROR", label: "ERROR"},\
+                {value: "WARN", label: "WARN"},\
+                {value: "INFO", label: "INFO"},\
+                {value: "DEBUG", label: "DEBUG"},\
+                {value: "TRACE", label: "TRACE"},\
+                {value: "ALL", label: "ALL"},\
+                {value: undefined, label: "Default"}\
+            ]',
+            'Level for internal log4j implementation')
+    .details-row
+        +dropdown-required('Logger configuration:', model + '.mode', '"log4jMode"', 'true', 'true', 'Choose logger mode',
+            '[\
+                {value: "Default", label: "Default"},\
+                {value: "Path", label: "Path"}\
+            ]',
+            'Choose logger configuration\
+            <ul>\
+                <li>Default - default logger</li>\
+                <li>Path - path or URI to XML configuration</li>\
+            </ul>')
+    .details-row(ng-show=pathRequired)
+        +text('Path:', model + '.path', '"log4jPath"', pathRequired, 'Input path', 'Path or URI to XML configuration')

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/frontend/app/modules/states/configuration/clusters/logger/log4j2.jade
----------------------------------------------------------------------
diff --git a/modules/web-console/frontend/app/modules/states/configuration/clusters/logger/log4j2.jade b/modules/web-console/frontend/app/modules/states/configuration/clusters/logger/log4j2.jade
new file mode 100644
index 0000000..8b9d3e1
--- /dev/null
+++ b/modules/web-console/frontend/app/modules/states/configuration/clusters/logger/log4j2.jade
@@ -0,0 +1,39 @@
+//-
+    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.jade
+
+-var form = 'logger'
+-var model = 'backupItem.logger.Log4j2'
+-var log4j2Required = 'backupItem.logger.kind === "Log4j2"'
+
+div
+    .details-row
+        +dropdown('Level:', model + '.level', '"log4j2Level"', 'true', 'Default',
+            '[\
+                {value: "OFF", label: "OFF"},\
+                {value: "FATAL", label: "FATAL"},\
+                {value: "ERROR", label: "ERROR"},\
+                {value: "WARN", label: "WARN"},\
+                {value: "INFO", label: "INFO"},\
+                {value: "DEBUG", label: "DEBUG"},\
+                {value: "TRACE", label: "TRACE"},\
+                {value: "ALL", label: "ALL"},\
+                {value: undefined, label: "Default"}\
+            ]',
+            'Level for internal log4j2 implementation')
+    .details-row
+        +text('Path:', model + '.path', '"log4j2Path"', log4j2Required, 'Input path', 'Path or URI to XML configuration')

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/frontend/app/modules/states/configuration/clusters/marshaller.jade
----------------------------------------------------------------------
diff --git a/modules/web-console/frontend/app/modules/states/configuration/clusters/marshaller.jade b/modules/web-console/frontend/app/modules/states/configuration/clusters/marshaller.jade
new file mode 100644
index 0000000..1fc3ce7
--- /dev/null
+++ b/modules/web-console/frontend/app/modules/states/configuration/clusters/marshaller.jade
@@ -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.jade
+
+-var form = 'marshaller'
+-var model = 'backupItem'
+-var marshaller = model + '.marshaller'
+-var optMarshaller = marshaller + '.OptimizedMarshaller'
+
+.panel.panel-default(ng-form=form novalidate)
+    .panel-heading(bs-collapse-toggle ng-click='ui.loadPanel("#{form}")')
+        ignite-form-panel-chevron
+        label Marshaller
+        ignite-form-field-tooltip.tipLabel
+            | Marshaller allows to marshal or unmarshal objects in grid#[br]
+            | It provides serialization/deserialization mechanism for all instances that are sent across networks or are otherwise serialized
+            | By default BinaryMarshaller will be used
+        ignite-form-revert
+    .panel-collapse(role='tabpanel' bs-collapse-target id=form)
+        .panel-body(ng-if='ui.isPanelLoaded("#{form}")')
+            .col-sm-6
+                .settings-row
+                    +dropdown('Marshaller:', marshaller + '.kind', '"kind"', 'true', 'Choose marshaller',
+                        '[\
+                            {value: "OptimizedMarshaller", label: "OptimizedMarshaller"},\
+                            {value: "JdkMarshaller", label: "JdkMarshaller"},\
+                            {value: undefined, label: "Not set"}\
+                        ]',
+                        'Instance of marshaller to use in grid<br/>\
+                        <ul>\
+                            <li>OptimizedMarshaller - Optimized implementation of marshaller</li>\
+                            <li>JdkMarshaller - Marshaller based on JDK serialization mechanism</li>\
+                            <li>Not set - BinaryMarshaller serialize and deserialize all objects in the binary format</li>\
+                        </ul>')
+                    a.customize(
+                        ng-if='#{marshaller}.kind && #{marshaller}.kind === "OptimizedMarshaller"'
+                        ng-click='#{marshaller}.expanded = !#{marshaller}.expanded'
+                    ) {{ #{marshaller}.expanded ? "Hide settings" : "Show settings"}}
+                .settings-row
+                    .panel-details(ng-show='#{marshaller}.expanded && #{marshaller}.kind === "OptimizedMarshaller"')
+                        .details-row
+                            +number('Streams pool size:', optMarshaller + '.poolSize', '"poolSize"', 'true', '0', '0',
+                                'Specifies size of cached object streams used by marshaller<br/>\
+                                Object streams are cached for performance reason to avoid costly recreation for every serialization routine<br/>\
+                                If 0 (default), pool is not used and each thread has its own cached object stream which it keeps reusing<br/>\
+                                Since each stream has an internal buffer, creating a stream for each thread can lead to high memory consumption if many large messages are marshalled or unmarshalled concurrently<br/>\
+                                Consider using pool in this case. This will limit number of streams that can be created and, therefore, decrease memory consumption<br/>\
+                                NOTE: Using streams pool can decrease performance since streams will be shared between different threads which will lead to more frequent context switching')
+                        .details-row
+                            +checkbox('Require serializable', optMarshaller + '.requireSerializable', '"requireSerializable"',
+                                'Whether marshaller should require Serializable interface or not')
+                .settings-row
+                    +checkbox('Marshal local jobs', model + '.marshalLocalJobs', '"marshalLocalJobs"', 'If this flag is enabled, jobs mapped to local node will be marshalled as if it was remote node')
+                .settings-row
+                    +number('Keep alive time:', model + '.marshallerCacheKeepAliveTime', '"marshallerCacheKeepAliveTime"', 'true', '10000', '0',
+                        'Keep alive time of thread pool that is in charge of processing marshaller messages')
+                .settings-row
+                    +number('Pool size:', model + '.marshallerCacheThreadPoolSize', '"marshallerCacheThreadPoolSize"', 'true', 'max(8, availableProcessors) * 2', '1',
+                        'Default size of thread pool that is in charge of processing marshaller messages')
+            .col-sm-6
+                +preview-xml-java(model, 'clusterMarshaller')

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/frontend/app/modules/states/configuration/clusters/metrics.jade
----------------------------------------------------------------------
diff --git a/modules/web-console/frontend/app/modules/states/configuration/clusters/metrics.jade b/modules/web-console/frontend/app/modules/states/configuration/clusters/metrics.jade
new file mode 100644
index 0000000..2b0dfd6
--- /dev/null
+++ b/modules/web-console/frontend/app/modules/states/configuration/clusters/metrics.jade
@@ -0,0 +1,51 @@
+//-
+    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.jade
+
+-var form = 'metrics'
+-var model = 'backupItem'
+
+.panel.panel-default(ng-form=form novalidate)
+    .panel-heading(bs-collapse-toggle ng-click='ui.loadPanel("#{form}")')
+        ignite-form-panel-chevron
+        label Metrics
+        ignite-form-field-tooltip.tipLabel
+            | Cluster runtime metrics settings
+        ignite-form-revert
+    .panel-collapse(role='tabpanel' bs-collapse-target id=form)
+        .panel-body(ng-if='ui.isPanelLoaded("#{form}")')
+            .col-sm-6
+                .settings-row
+                    +number('Elapsed time:', model + '.metricsExpireTime', '"metricsExpireTime"', 'true', 'Long.MAX_VALUE', '1',
+                        'Time in milliseconds after which a certain metric value is considered expired')
+                .settings-row
+                    +number('History size:', model + '.metricsHistorySize', '"metricsHistorySize"', 'true', '10000', '1',
+                        'Number of metrics kept in history to compute totals and averages')
+                .settings-row
+                    +number('Log frequency:', model + '.metricsLogFrequency', '"metricsLogFrequency"', 'true', '60000', '0',
+                        'Frequency of metrics log print out<br/>\ ' +
+                        'When <b>0</b> log print of metrics is disabled')
+                .settings-row
+                    +number('Update frequency:', model + '.metricsUpdateFrequency', '"metricsUpdateFrequency"', 'true', '2000', '0',
+                        'Job metrics update frequency in milliseconds\
+                        <ul>\
+                            <li>If set to -1 job metrics are never updated</li>\
+                            <li>If set to 0 job metrics are updated on each job start and finish</li>\
+                            <li>Positive value defines the actual update frequency</li>\
+                        </ul>')
+            .col-sm-6
+                +preview-xml-java(model, 'clusterMetrics')

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/frontend/app/modules/states/configuration/clusters/ssl.jade
----------------------------------------------------------------------
diff --git a/modules/web-console/frontend/app/modules/states/configuration/clusters/ssl.jade b/modules/web-console/frontend/app/modules/states/configuration/clusters/ssl.jade
new file mode 100644
index 0000000..7264386
--- /dev/null
+++ b/modules/web-console/frontend/app/modules/states/configuration/clusters/ssl.jade
@@ -0,0 +1,109 @@
+//-
+    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.jade
+
+-var form = 'sslConfiguration'
+-var cluster = 'backupItem'
+-var enabled = 'backupItem.sslEnabled'
+-var model = cluster + '.sslContextFactory'
+-var trust = model + '.trustManagers'
+
+.panel.panel-default(ng-form=form novalidate)
+    .panel-heading(bs-collapse-toggle ng-click='ui.loadPanel("#{form}")')
+        ignite-form-panel-chevron
+        label(id='sslConfiguration-title') SSL configuration
+        ignite-form-field-tooltip.tipLabel
+            | Settings for SSL configuration for creating a secure socket layer
+        ignite-form-revert
+    .panel-collapse(role='tabpanel' bs-collapse-target id=form)
+        .panel-body(ng-if='ui.isPanelLoaded("#{form}")')
+            .col-sm-6
+                .settings-row
+                    +checkbox('Enabled', enabled, '"sslEnabled"', 'Flag indicating whether to configure SSL configuration')
+                .settings-row
+                    +text-options('Algorithm to create a key manager:', model + '.keyAlgorithm', '"keyAlgorithm"', '["SumX509", "X509"]', enabled, 'false', 'SumX509',
+                        'Sets key manager algorithm that will be used to create a key manager<br/>\
+                        Notice that in most cased default value suites well, however, on Android platform this value need to be set to X509')
+                .settings-row
+                    +text-enabled('Key store file:', model + '.keyStoreFilePath', '"keyStoreFilePath"', enabled, enabled, 'Path to the key store file',
+                        'Path to the key store file<br/>\
+                        This is a mandatory parameter since ssl context could not be initialized without key manager')
+                .settings-row
+                    +text-options('Key store type:', model + '.keyStoreType', '"keyStoreType"', '["JKS", "PCKS11", "PCKS12"]', enabled, 'false', 'JKS',
+                        'Key store type used in context initialization')
+                .settings-row
+                    +text-options('Protocol:', model + '.protocol', '"protocol"', '["TSL", "SSL"]', enabled, 'false', 'TSL', 'Protocol for secure transport')
+                .settings-row
+                    -var form = 'trustManagers'
+
+                    +ignite-form-group(ng-form=form ng-model=trust)
+                        -var uniqueTip = 'Such trust manager already exists!'
+
+                        ignite-form-field-label
+                            | Trust managers
+                        ignite-form-group-tooltip
+                            | Pre-configured trust managers
+                        ignite-form-group-add(ng-show='#{enabled}' ng-click='(group.add = [{}])')
+                            | Add new trust manager.
+
+                        .group-content(ng-if='#{trust}.length')
+                            -var model = 'obj.model';
+                            -var name = '"edit" + $index'
+                            -var valid = form + '[' + name + '].$valid'
+                            -var save = trust + '[$index] = ' + model
+                
+                            div(ng-show=enabled)
+                                div(ng-repeat='model in #{trust} track by $index' ng-init='obj = {}')
+                                    label.col-xs-12.col-sm-12.col-md-12
+                                        .indexField
+                                            | {{ $index+1 }})
+                                        +table-remove-conditional-button(trust, enabled, 'Remove trust manager')
+                                        span(ng-hide='field.edit')
+                                            a.labelFormField(ng-click='#{enabled} && (field.edit = true) && (#{model} = model)') {{ model }}
+                                        span(ng-if='field.edit')
+                                            +table-java-class-field('Trust manager:', name, model, trust, valid, save, false)
+                                                +table-save-button(valid, save, false)
+                                                +unique-feedback(name, uniqueTip)
+                            div(ng-hide=enabled)
+                                div(ng-repeat='model in #{trust} track by $index')
+                                    label.col-xs-12.col-sm-12.col-md-12
+                                        .labelFormField.labelField
+                                            | {{ $index+1 }})
+                                        span.labelFormField
+                                            | {{ model }}
+
+                        .group-content(ng-repeat='field in group.add')
+                            -var model = 'new';
+                            -var name = '"new"'
+                            -var valid = form + '[' + name + '].$valid'
+                            -var save = trust + '.push(' + model + ')'
+ 
+                            div
+                                label.col-xs-12.col-sm-12.col-md-12
+                                    +table-java-class-field('Trust manager', name, model, trust, valid, save, true)
+                                        +table-save-button(valid, save, true)
+                                        +unique-feedback(name, uniqueTip)
+
+                        .group-content-empty(ng-if='!(#{trust}.length) && !group.add.length')
+                            | Not defined
+
+                .settings-row(ng-show='!#{trust}.length')
+                    +text-enabled('Trust store file:', model + '.trustStoreFilePath', '"trustStoreFilePath"', enabled, 'false', 'Path to the trust store file', 'Path to the trust store file')
+                .settings-row(ng-show='!#{trust}.length')
+                    +text-options('Trust store type:', model + '.trustStoreType', '"trustStoreType"', '["JKS", "PCKS11", "PCKS12"]', enabled, 'false', 'JKS', 'Trust store type used in context initialization')
+            .col-sm-6
+                +preview-xml-java(cluster, 'clusterSsl')

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/frontend/app/modules/states/configuration/clusters/swap.jade
----------------------------------------------------------------------
diff --git a/modules/web-console/frontend/app/modules/states/configuration/clusters/swap.jade b/modules/web-console/frontend/app/modules/states/configuration/clusters/swap.jade
new file mode 100644
index 0000000..1c75c4f
--- /dev/null
+++ b/modules/web-console/frontend/app/modules/states/configuration/clusters/swap.jade
@@ -0,0 +1,71 @@
+//-
+    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.jade
+
+-var form = 'swap'
+-var model = 'backupItem'
+-var swapModel = model + '.swapSpaceSpi'
+-var fileSwapModel = swapModel + '.FileSwapSpaceSpi'
+
+.panel.panel-default(ng-form=form novalidate)
+    .panel-heading(bs-collapse-toggle ng-click='ui.loadPanel("#{form}")')
+        ignite-form-panel-chevron
+        label Swap
+        ignite-form-field-tooltip.tipLabel
+            | Settings for overflow data to disk if it cannot fit in memory
+        ignite-form-revert
+    .panel-collapse(role='tabpanel' bs-collapse-target id=form)
+        .panel-body(ng-if='ui.isPanelLoaded("#{form}")')
+            .col-sm-6
+                .settings-row
+                    +dropdown('Swap space SPI:', swapModel + '.kind', '"swapSpaceSpi"', 'true', 'Choose swap SPI',
+                        '[\
+                            {value: "FileSwapSpaceSpi", label: "File-based swap"},\
+                            {value: undefined, label: "Not set"}\
+                        ]',
+                        'Provides a mechanism in grid for storing data on disk<br/>\
+                        Ignite cache uses swap space to overflow data to disk if it cannot fit in memory\
+                        <ul>\
+                            <li>File-based swap - File-based swap space SPI implementation which holds keys in memory</li>\
+                            <li>Not set - File-based swap space SPI with default configuration when it needed</li>\
+                        </ul>')
+                    a.customize(
+                        ng-if='#{swapModel}.kind'
+                        ng-click='#{swapModel}.expanded = !#{swapModel}.expanded'
+                    ) {{ #{swapModel}.expanded ? "Hide settings" : "Show settings"}}
+                .settings-row
+                    .panel-details(ng-show='#{swapModel}.expanded && #{swapModel}.kind')
+                        .details-row
+                            +text('Base directory:', fileSwapModel + '.baseDirectory', '"baseDirectory"', 'false', 'swapspace',
+                                'Base directory where to write files')
+                        .details-row
+                            +number('Read stripe size:', fileSwapModel + '.readStripesNumber', '"readStripesNumber"', 'true', 'availableProcessors', '0',
+                                'Read stripe size defines number of file channels to be used concurrently')
+                        .details-row
+                            +number-min-max-step('Maximum sparsity:', fileSwapModel + '.maximumSparsity', '"maximumSparsity"', 'true', '0.5', '0', '0.999', '0.05',
+                                'This property defines maximum acceptable wasted file space to whole file size ratio<br/>\
+                                When this ratio becomes higher than specified number compacting thread starts working')
+                        .details-row
+                            +number('Max write queue size:', fileSwapModel + '.maxWriteQueueSize', '"maxWriteQueueSize"', 'true', '1024 * 1024', '0',
+                                'Max write queue size in bytes<br/>\
+                                If there are more values are waiting for being written to disk then specified size, SPI will block on store operation')
+                        .details-row
+                            +number('Write buffer size:', fileSwapModel + '.writeBufferSize', '"writeBufferSize"', 'true', '64 * 1024', '0',
+                                'Write buffer size in bytes<br/>\
+                                Write to disk occurs only when this buffer is full')
+            .col-sm-6
+                +preview-xml-java(model, 'clusterSwap')

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/frontend/app/modules/states/configuration/clusters/thread.jade
----------------------------------------------------------------------
diff --git a/modules/web-console/frontend/app/modules/states/configuration/clusters/thread.jade b/modules/web-console/frontend/app/modules/states/configuration/clusters/thread.jade
new file mode 100644
index 0000000..9669a87
--- /dev/null
+++ b/modules/web-console/frontend/app/modules/states/configuration/clusters/thread.jade
@@ -0,0 +1,48 @@
+//-
+    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.jade
+
+-var form = 'pools'
+-var model = 'backupItem'
+
+.panel.panel-default(ng-form=form novalidate)
+    .panel-heading(bs-collapse-toggle ng-click='ui.loadPanel("#{form}")')
+        ignite-form-panel-chevron
+        label Thread pools size
+        ignite-form-field-tooltip.tipLabel
+            | Settings for node thread pools
+        ignite-form-revert
+    .panel-collapse(role='tabpanel' bs-collapse-target id=form)
+        .panel-body(ng-if='ui.isPanelLoaded("#{form}")')
+            .col-sm-6
+                .settings-row
+                    +number('Public:', model + '.publicThreadPoolSize', '"publicThreadPoolSize"', 'true', 'max(8, availableProcessors) * 2', '1',
+                        'Thread pool that is in charge of processing ComputeJob, GridJobs and user messages sent to node')
+                .settings-row
+                    +number('System:', model + '.systemThreadPoolSize', '"systemThreadPoolSize"', 'true', 'max(8, availableProcessors) * 2', '1',
+                        'Thread pool that is in charge of processing internal system messages')
+                .settings-row
+                    +number('Management:', model + '.managementThreadPoolSize', '"managementThreadPoolSize"', 'true', '4', '1',
+                        'Thread pool that is in charge of processing internal and Visor ComputeJob, GridJobs')
+                .settings-row
+                    +number('IGFS:', model + '.igfsThreadPoolSize', '"igfsThreadPoolSize"', 'true', 'availableProcessors', '1',
+                        'Thread pool that is in charge of processing outgoing IGFS messages')
+                .settings-row
+                    +number('Rebalance:', model + '.rebalanceThreadPoolSize', '"rebalanceThreadPoolSize"', 'true', '1', '1',
+                        'Max count of threads can be used at rebalancing')
+            .col-sm-6
+                +preview-xml-java(model, 'clusterPools')

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/frontend/app/modules/states/configuration/clusters/time.jade
----------------------------------------------------------------------
diff --git a/modules/web-console/frontend/app/modules/states/configuration/clusters/time.jade b/modules/web-console/frontend/app/modules/states/configuration/clusters/time.jade
new file mode 100644
index 0000000..813948d
--- /dev/null
+++ b/modules/web-console/frontend/app/modules/states/configuration/clusters/time.jade
@@ -0,0 +1,47 @@
+//-
+    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.jade
+
+-var form = 'time'
+-var model = 'backupItem'
+
+.panel.panel-default(ng-form=form novalidate)
+    .panel-heading(bs-collapse-toggle ng-click='ui.loadPanel("#{form}")')
+        ignite-form-panel-chevron
+        label Time configuration
+        ignite-form-field-tooltip.tipLabel
+            | Time settings for CLOCK write ordering mode
+        ignite-form-revert
+    .panel-collapse(role='tabpanel' bs-collapse-target id=form)
+        .panel-body(ng-if='ui.isPanelLoaded("#{form}")')
+            .col-sm-6
+                .settings-row
+                    +number('Samples size:', model + '.clockSyncSamples', '"clockSyncSamples"', 'true', '8', '0',
+                        'Number of samples used to synchronize clocks between different nodes<br/>\
+                        Clock synchronization is used for cache version assignment in CLOCK order mode')
+                .settings-row
+                    +number('Frequency:', model + '.clockSyncFrequency', '"clockSyncFrequency"', 'true', '120000', '0',
+                        'Frequency at which clock is synchronized between nodes, in milliseconds<br/>\
+                        Clock synchronization is used for cache version assignment in CLOCK order mode')
+                .settings-row
+                    +number-min-max('Port base:', model + '.timeServerPortBase', '"timeServerPortBase"', 'true', '31100', '0', '65535',
+                        'Time server provides clock synchronization between nodes<br/>\
+                        Base UPD port number for grid time server. Time server will be started on one of free ports in range')
+                .settings-row
+                    +number('Port range:', model + '.timeServerPortRange', '"timeServerPortRange"', 'true', '100', '1', 'Time server port range')
+            .col-sm-6
+                +preview-xml-java(model, 'clusterTime')

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/frontend/app/modules/states/configuration/clusters/transactions.jade
----------------------------------------------------------------------
diff --git a/modules/web-console/frontend/app/modules/states/configuration/clusters/transactions.jade b/modules/web-console/frontend/app/modules/states/configuration/clusters/transactions.jade
new file mode 100644
index 0000000..d9611a5
--- /dev/null
+++ b/modules/web-console/frontend/app/modules/states/configuration/clusters/transactions.jade
@@ -0,0 +1,69 @@
+//-
+    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.jade
+
+-var form = 'transactions'
+-var model = 'backupItem.transactionConfiguration'
+
+.panel.panel-default(ng-form=form novalidate)
+    .panel-heading(bs-collapse-toggle ng-click='ui.loadPanel("#{form}")')
+        ignite-form-panel-chevron
+        label Transactions
+        ignite-form-field-tooltip.tipLabel
+            | Settings for transactions
+        ignite-form-revert
+    .panel-collapse(role='tabpanel' bs-collapse-target id=form)
+        .panel-body(ng-if='ui.isPanelLoaded("#{form}")')
+            .col-sm-6
+                .settings-row
+                    +dropdown('Concurrency:', model + '.defaultTxConcurrency', '"defaultTxConcurrency"', 'true', 'PESSIMISTIC',
+                        '[\
+                            {value: "OPTIMISTIC", label: "OPTIMISTIC"},\
+                            {value: "PESSIMISTIC", label: "PESSIMISTIC"}\
+                        ]',
+                        'Cache transaction concurrency to use when one is not explicitly specified\
+                        <ul>\
+                            <li>OPTIMISTIC - All cache operations are not distributed to other nodes until commit is called</li>\
+                            <li>PESSIMISTIC - A lock is acquired on all cache operations with exception of read operations in READ_COMMITTED mode</li>\
+                        </ul>\
+                        ')
+                .settings-row
+                    +dropdown('Isolation:', model + '.defaultTxIsolation', '"defaultTxIsolation"', 'true', 'REPEATABLE_READ',
+                        '[\
+                            {value: "READ_COMMITTED", label: "READ_COMMITTED"},\
+                            {value: "REPEATABLE_READ", label: "REPEATABLE_READ"},\
+                            {value: "SERIALIZABLE", label: "SERIALIZABLE"}\
+                        ]',
+                        'Default transaction isolation\
+                        <ul>\
+                            <li>READ_COMMITTED - Always a committed value will be provided for read operations</li>\
+                            <li>REPEATABLE_READ - If a value was read once within transaction, then all consecutive reads will provide the same in-transaction value</li>\
+                            <li>SERIALIZABLE - All transactions occur in a completely isolated fashion, as if all transactions in the system had executed serially, one after the other.</li>\
+                        </ul>')
+                .settings-row
+                    +number('Default timeout:', model + '.defaultTxTimeout', '"defaultTxTimeout"', 'true', '0', '0', 'Default transaction timeout')
+                .settings-row
+                    +number('Pessimistic log cleanup delay:', model + '.pessimisticTxLogLinger', '"pessimisticTxLogLinger"', 'true', '10000', '0',
+                        'Delay, in milliseconds, after which pessimistic recovery entries will be cleaned up for failed node')
+                .settings-row
+                    +number('Pessimistic log size:', model + '.pessimisticTxLogSize', '"pessimisticTxLogSize"', 'true', '0', '0',
+                        'Size of pessimistic transactions log stored on node in order to recover transaction commit if originating node has left grid before it has sent all messages to transaction nodes')
+                .settings-row
+                    +java-class('Manager factory:', model + '.txManagerFactory', '"txManagerFactory"', 'true', 'false',
+                        'Class name of transaction manager factory for integration with JEE app servers')
+            .col-sm-6
+                +preview-xml-java(model, 'clusterTransactions')

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/frontend/app/modules/states/configuration/domains/general.jade
----------------------------------------------------------------------
diff --git a/modules/web-console/frontend/app/modules/states/configuration/domains/general.jade b/modules/web-console/frontend/app/modules/states/configuration/domains/general.jade
new file mode 100644
index 0000000..5c55e0c
--- /dev/null
+++ b/modules/web-console/frontend/app/modules/states/configuration/domains/general.jade
@@ -0,0 +1,46 @@
+//-
+    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.jade
+
+- var form = 'general'
+- var model = 'backupItem'
+
+.panel.panel-default(ng-form=form novalidate)
+    .panel-heading(bs-collapse-toggle)
+        ignite-form-panel-chevron
+        label General
+        ignite-form-field-tooltip.tipLabel
+            | Domain model properties common for Query and Store
+        ignite-form-revert
+    .panel-collapse(role='tabpanel' bs-collapse-target id=form)
+        .panel-body
+            .col-sm-6
+                .settings-row
+                    +caches(model, 'Select caches to associate domain model with cache')
+                .settings-row
+                    +dropdown-required('Query metadata:', model + '.queryMetadata', '"queryMetadata"', 'true', 'true', '', 'queryMetadataVariants',
+                        'Query metadata configured with:\
+                        <ul>\
+                            <li>Java annotations like @QuerySqlField</li>\
+                            <li>Configuration via QueryEntity class</li>\
+                        </ul>')
+                .settings-row
+                    +java-class-typeahead('Key type:', model + '.keyType', '"keyType"', 'javaBuiltInClasses', 'true', 'true', 'Full class name for Key', 'Key class used to store key in cache')
+                .settings-row
+                    +java-class('Value type:', model + '.valueType', '"valueType"', 'true', 'true', 'Value class used to store value in cache')
+            .col-sm-6
+                +preview-xml-java(model, 'domainModelGeneral')

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/frontend/app/modules/states/configuration/domains/query.jade
----------------------------------------------------------------------
diff --git a/modules/web-console/frontend/app/modules/states/configuration/domains/query.jade b/modules/web-console/frontend/app/modules/states/configuration/domains/query.jade
new file mode 100644
index 0000000..33c358a
--- /dev/null
+++ b/modules/web-console/frontend/app/modules/states/configuration/domains/query.jade
@@ -0,0 +1,170 @@
+//-
+    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.jade
+
+- var form = 'query'
+- var model = 'backupItem'
+- var queryFields = model + '.fields'
+- var queryAliases = model + '.aliases'
+- var queryIndexes = model + '.indexes'
+- var queryFieldsForm = 'queryFields'
+- var queryAliasesForm = 'queryAliases'
+- var queryIndexesForm = 'queryIndexes'
+
+// LEGACY mixin for LEGACY index fields table.
+mixin table-index-item-edit(prefix, index, sortAvailable, idAddition)
+    -var fieldName = prefix + 'FieldName'
+    -var direction = prefix + 'Direction'
+
+    -var fieldNameModel = 'indexesTbl.' + fieldName
+    -var directionModel = 'indexesTbl.' + direction
+
+    -var btnVisible = 'tableIndexItemSaveVisible(indexesTbl, ' + index + ')'
+    -var btnSave = 'tableIndexItemSave(indexesTbl, itemIndex, ' + index + ')'
+    -var btnVisibleAndSave = btnVisible + ' && ' + btnSave
+
+    .col-xs-8.col-sm-8.col-md-8(ng-show=sortAvailable)
+        label.fieldSep /
+        .input-tip
+            input.form-control(id='{{::"#{fieldName}S" + #{idAddition}}}' ignite-on-enter-focus-move='{{::"#{direction}S" + #{idAddition}}}' type='text' ng-model=fieldNameModel placeholder='Field name' ignite-on-escape='tableReset()')
+    .col-xs-4.col-sm-4.col-md-4(ng-show=sortAvailable)
+        +btn-save(btnVisible, btnSave)
+        .input-tip
+            button.select-toggle.form-control(id='{{::"#{direction}S" + #{idAddition}}}' ng-model=directionModel bs-select bs-options='item.value as item.label for item in {{sortDirections}}' ignite-on-enter=btnVisibleAndSave ignite-on-escape='tableReset()' tabindex='0')
+    .col-xs-12(ng-show='!(#{sortAvailable})')
+        +btn-save(btnVisible, btnSave)
+        .input-tip
+            input.form-control(id='{{::"#{fieldName}" + #{idAddition}}}' type='text' ng-model=fieldNameModel placeholder='Field name' ignite-on-enter=btnVisibleAndSave ignite-on-escape='tableReset()')
+
+.panel.panel-default(ng-form=form novalidate)
+    .panel-heading(bs-collapse-toggle)
+        ignite-form-panel-chevron
+        label(id='query-title') Domain model for SQL query
+        ignite-form-field-tooltip.tipLabel
+            | Domain model properties for fields queries
+        ignite-form-revert
+    .panel-collapse(role='tabpanel' bs-collapse-target id='query')
+        .panel-body
+            .col-sm-6
+                .content-not-available(ng-if='#{model}.queryMetadata === "Annotations"')
+                    label Not available for annotated types
+                div(ng-if='#{model}.queryMetadata === "Configuration"')
+                    .settings-row
+                        +ignite-form-group(ng-model='#{queryFields}' ng-form='#{queryFieldsForm}')
+                            ignite-form-field-label(id='queryFields')
+                                | Fields
+                            ignite-form-group-tooltip
+                                | Collection of name-to-type mappings to be queried, in addition to indexed fields
+                            ignite-form-group-add(ng-click='tableNewItem(queryFieldsTbl)')
+                                | Add field to query
+                            .group-content-empty(ng-if='!((#{queryFields} && #{queryFields}.length > 0) || tableNewItemActive(queryFieldsTbl))')
+                                | Not defined
+                            .group-content(ng-show='(#{queryFields} && #{queryFields}.length > 0) || tableNewItemActive(queryFieldsTbl)')
+                                table.links-edit(id='fields' st-table=queryFields)
+                                    tbody
+                                        tr(ng-repeat='item in #{queryFields}')
+                                            td.col-sm-12(ng-show='!tableEditing(queryFieldsTbl, $index)')
+                                                a.labelFormField(ng-click='tableStartEdit(backupItem, queryFieldsTbl, $index)') {{item.name}}  / {{item.className}}
+                                                +btn-remove('tableRemove(backupItem, queryFieldsTbl, $index)', '"Remove path"')
+                                            td.col-sm-12(ng-show='tableEditing(queryFieldsTbl, $index)')
+                                                +table-pair-edit('queryFieldsTbl', 'cur', 'Field name', 'Field full class name', false, true, '{{::queryFieldsTbl.focusId + $index}}', '$index', '/')
+                                    tfoot(ng-show='tableNewItemActive(queryFieldsTbl)')
+                                        tr
+                                            td.col-sm-12
+                                                +table-pair-edit('queryFieldsTbl', 'new', 'Field name', 'Field full class name', false, true, '{{::queryFieldsTbl.focusId + $index}}', '-1', '/')
+                    .settings-row
+                        +ignite-form-group(ng-model='#{queryAliases}' ng-form='#{queryAliasesForm}')
+                            ignite-form-field-label
+                                | Aliases
+                            ignite-form-group-tooltip
+                                | Mapping from full property name in dot notation to an alias that will be used as SQL column name
+                                | For example: "parent.name" as "parentName"
+                            ignite-form-group-add(ng-click='tableNewItem(aliasesTbl)')
+                                | Add alias to query
+                            .group-content-empty(ng-if='!((#{queryAliases} && #{queryAliases}.length > 0) || tableNewItemActive(aliasesTbl))')
+                                | Not defined
+                            .group-content(ng-show='(#{queryAliases} && #{queryAliases}.length > 0) || tableNewItemActive(aliasesTbl)')
+                                table.links-edit(id='aliases' st-table=queryAliases)
+                                    tbody
+                                        tr(ng-repeat='item in #{queryAliases}')
+                                            td.col-sm-12(ng-show='!tableEditing(aliasesTbl, $index)')
+                                                a.labelFormField(ng-click='tableStartEdit(backupItem, aliasesTbl, $index)') {{item.field}} &rarr; {{item.alias}}
+                                                +btn-remove('tableRemove(backupItem, aliasesTbl, $index)', '"Remove alias"')
+                                            td.col-sm-12(ng-show='tableEditing(aliasesTbl, $index)')
+                                                +table-pair-edit('aliasesTbl', 'cur', 'Field name', 'Field Alias', false, false, '{{::aliasesTbl.focusId + $index}}', '$index', '&rarr;')
+                                    tfoot(ng-show='tableNewItemActive(aliasesTbl)')
+                                        tr
+                                            td.col-sm-12
+                                                +table-pair-edit('aliasesTbl', 'new', 'Field name', 'Field Alias', false, false, '{{::aliasesTbl.focusId + $index}}', '-1', '&rarr;')
+                    .settings-row(ng-init='indexesTbl={type: "table-indexes", model: "indexes", focusId: "IndexName", ui: "table-indexes"}')
+                        +ignite-form-group(ng-model='#{queryIndexes}' ng-form='#{queryIndexesForm}')
+                            ignite-form-field-label
+                                | Indexes
+                            ignite-form-group-tooltip
+                                | Collection of indexes
+                            ignite-form-group-add(ng-click='tableNewItem(indexesTbl)')
+                                | Add new index
+                            .group-content-empty(id='indexes-add' ng-show='!((#{queryIndexes} && #{queryIndexes}.length > 0) || tableNewItemActive(indexesTbl))')
+                                | Not defined
+                            .group-content(ng-show='(#{queryIndexes} && #{queryIndexes}.length > 0) || tableNewItemActive(indexesTbl)')
+                                -var btnVisibleAndSave = 'tableIndexSaveVisible(indexesTbl, $index) && tableIndexSave(indexesTbl, $index)'
+
+                                table.links-edit(st-table=queryIndexes ng-init='newDirection = false')
+                                    tbody
+                                        tr(ng-repeat='item in #{queryIndexes}')
+                                            td
+                                                .col-sm-12(ng-show='!tableEditing(indexesTbl, $index)')
+                                                    a.labelFormField(id='indexes{{$index}}' ng-click='tableStartEdit(backupItem, indexesTbl, $index)') {{$index + 1}}) {{item.name}} [{{item.indexType}}]
+                                                    +btn-remove('tableRemove(backupItem, indexesTbl, $index)', '"Remove index"')
+                                                    +btn-add('tableIndexNewItem(indexesTbl, $index)', '"Add new field to index"')
+                                                div(ng-show='tableEditing(indexesTbl, $index)')
+                                                    .col-sm-7
+                                                        label.fieldSep /
+                                                        .input-tip
+                                                            input.form-control(id='curIndexName{{$index}}' type='text' ignite-on-enter-focus-move='curIndexType{{$index}}' ng-model='indexesTbl.curIndexName' placeholder='Index name' ignite-on-enter=btnVisibleAndSave ignite-on-escape='tableReset()')
+                                                    .col-sm-5
+                                                        +btn-save('tableIndexSaveVisible(indexesTbl, $index)', 'tableIndexSave(indexesTbl, $index)')
+                                                        .input-tip
+                                                            button.select-toggle.form-control(id='curIndexType{{$index}}' bs-select ng-model='indexesTbl.curIndexType' data-placeholder='Select index type' bs-options='item.value as item.label for item in indexType' tabindex='0' ignite-on-enter=btnVisibleAndSave ignite-on-escape='tableReset()')
+                                                .margin-left-dflt
+                                                    table.links-edit-sub(st-table='item.fields' ng-init='itemIndex = $index')
+                                                        tbody
+                                                            tr(ng-repeat='itemItem in item.fields')
+                                                                td
+                                                                    div(ng-show='!tableIndexItemEditing(indexesTbl, itemIndex, $index)')
+                                                                        a.labelFormField(ng-if='item.indexType == "SORTED"' ng-click='tableIndexItemStartEdit(indexesTbl, itemIndex, $index)') {{$index + 1}}) {{itemItem.name}} / {{itemItem.direction ? "ASC" : "DESC"}}
+                                                                        a.labelFormField(ng-if='item.indexType != "SORTED"' ng-click='tableIndexItemStartEdit(indexesTbl, itemIndex, $index)') {{$index + 1}}) {{itemItem.name}}
+                                                                        +btn-remove('tableRemoveIndexItem(item, $index)', '"Remove field from index"')
+                                                                    div(ng-show='tableIndexItemEditing(indexesTbl, itemIndex, $index)')
+                                                                        +table-index-item-edit('cur', '$index', 'item.indexType == "SORTED"', 'itemIndex + "-" + $index')
+                                                        tfoot(ng-show='tableIndexNewItemActive(indexesTbl, itemIndex)')
+                                                            tr(style='padding-left: 18px')
+                                                                td
+                                                                    +table-index-item-edit('new', '-1', 'item.indexType == "SORTED"', 'itemIndex')
+                                    tfoot(ng-show='tableNewItemActive(indexesTbl)')
+                                        tr
+                                            td
+                                                .col-sm-7
+                                                    .fieldSep /
+                                                    .input-tip
+                                                        input#newIndexName.form-control(type='text' ignite-on-enter-focus-move='newIndexType' ng-model='indexesTbl.newIndexName' placeholder='Index name' ignite-on-enter='tableIndexSaveVisible(indexesTbl, -1) && tableIndexSave(indexesTbl, -1)' ignite-on-escape='tableReset()')
+                                                .col-sm-5
+                                                    +btn-save('tableIndexSaveVisible(indexesTbl, -1)', 'tableIndexSave(indexesTbl, -1)')
+                                                    .input-tip
+                                                        button#newIndexType.select-toggle.form-control(bs-select ng-model='indexesTbl.newIndexType' data-placeholder='Select index type' bs-options='item.value as item.label for item in indexType' tabindex='0' ignite-on-enter=btnVisibleAndSave ignite-on-escape='tableReset()')
+            .col-sm-6
+                +preview-xml-java(model, 'domainModelQuery')

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/frontend/app/modules/states/configuration/domains/store.jade
----------------------------------------------------------------------
diff --git a/modules/web-console/frontend/app/modules/states/configuration/domains/store.jade b/modules/web-console/frontend/app/modules/states/configuration/domains/store.jade
new file mode 100644
index 0000000..96913bb
--- /dev/null
+++ b/modules/web-console/frontend/app/modules/states/configuration/domains/store.jade
@@ -0,0 +1,126 @@
+//-
+    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.jade
+
+-var form = 'store'
+-var model = 'backupItem'
+-var keyFields = model + '.keyFields'
+-var valueFields = model + '.valueFields'
+-var keyFieldsForm = 'storeKeyFields'
+-var valueFieldsForm = 'storeValueFields'
+
+//- LEGACY mixin for LEGACY db fields tables.
+mixin table-db-field-edit(tbl, prefix, focusId, index)
+    -var databaseName = prefix + 'DatabaseFieldName'
+    -var databaseType = prefix + 'DatabaseFieldType'
+    -var javaName = prefix + 'JavaFieldName'
+    -var javaType = prefix + 'JavaFieldType'
+
+    -var databaseNameModel = tbl + '.' + databaseName
+    -var databaseTypeModel = tbl + '.' + databaseType
+    -var javaNameModel = tbl + '.' + javaName
+    -var javaTypeModel = tbl + '.' + javaType
+
+    -var databaseNameId = databaseName + focusId
+    -var databaseTypeId = databaseType + focusId
+    -var javaNameId = javaName + focusId
+    -var javaTypeId = javaType + focusId
+
+    .col-xs-3.col-sm-3.col-md-3
+        .fieldSep /
+        .input-tip
+            input.form-control(id=databaseNameId ignite-on-enter-focus-move=databaseTypeId type='text' ng-model=databaseNameModel placeholder='DB name' ignite-on-enter='#{javaNameModel} = #{javaNameModel} ? #{javaNameModel} : #{databaseNameModel}' ignite-on-escape='tableReset()')
+    .col-xs-3.col-sm-3.col-md-3
+        .fieldSep /
+        .input-tip
+            button.select-toggle.form-control(id=databaseTypeId ignite-on-enter-focus-move=javaNameId ng-model=databaseTypeModel data-placeholder='DB type' ng-class='{placeholder: !#{databaseTypeModel}}' bs-select bs-options='item.value as item.label for item in {{supportedJdbcTypes}}' ignite-on-escape='tableReset()' tabindex='0')
+    .col-xs-3.col-sm-3.col-md-3
+        .fieldSep /
+        .input-tip
+            input.form-control(id=javaNameId ignite-on-enter-focus-move=javaTypeId type='text' ng-model=javaNameModel placeholder='Java name' ignite-on-escape='tableReset()')
+    .col-xs-3.col-sm-3.col-md-3
+        -var btnVisible = 'tableDbFieldSaveVisible(' + tbl + ', ' + index +')'
+        -var btnSave = 'tableDbFieldSave(' + tbl + ', ' + index +')'
+        -var btnVisibleAndSave = btnVisible + ' && ' + btnSave
+
+        +btn-save(btnVisible, btnSave)
+        .input-tip
+            button.select-toggle.form-control(id=javaTypeId ng-model=javaTypeModel data-placeholder='Java type' ng-class='{placeholder: !#{javaTypeModel}}' bs-select bs-options='item.value as item.label for item in {{supportedJavaTypes}}' ignite-on-enter=btnVisibleAndSave ignite-on-escape='tableReset()' tabindex='0')
+
+.panel.panel-default(ng-form=form novalidate)
+    .panel-heading(bs-collapse-toggle='' ng-click='ui.loadPanel("#{form}")')
+        ignite-form-panel-chevron
+        label Domain model for cache store
+        ignite-form-field-tooltip.tipLabel
+            | Domain model properties for binding database with cache via POJO cache store
+        ignite-form-revert
+    .panel-collapse(role='tabpanel' bs-collapse-target id=form)
+        .panel-body(ng-if='ui.isPanelLoaded("#{form}")')
+            .col-sm-6
+                .settings-row
+                    +text('Database schema:', model + '.databaseSchema', '"databaseSchema"', 'false', 'Input DB schema name', 'Schema name in database')
+                .settings-row
+                    +text('Database table:', model + '.databaseTable', '"databaseTable"', 'false', 'Input DB table name', 'Table name in database')
+                .settings-row(ng-init='keysTbl={type: "table-db-fields", model: "keyFields", focusId: "KeyField", ui: "table-db-fields"}')
+                    +ignite-form-group(ng-form=keyFieldsForm ng-model=keyFields)
+                        ignite-form-field-label(id='keyFields')
+                            | Key fields
+                        ignite-form-group-tooltip
+                            | Collection of key fields descriptions for CacheJdbcPojoStore
+                        ignite-form-group-add(ng-click='tableNewItem(keysTbl)')
+                            | Add key field
+                        .group-content-empty(ng-show='!((#{keyFields} && #{keyFields}.length > 0) || tableNewItemActive(keysTbl))') Not defined
+                        .group-content(ng-show='(#{keyFields} && #{keyFields}.length > 0) || tableNewItemActive(keysTbl)')
+                            table.links-edit(st-table=keyFields)
+                                tbody
+                                    tr(ng-repeat='item in #{keyFields}')
+                                        td
+                                            div(ng-show='!tableEditing(keysTbl, $index)')
+                                                a.labelFormField(ng-click='tableStartEdit(backupItem, keysTbl, $index)') {{$index + 1}}) {{item.databaseFieldName}} / {{item.databaseFieldType}} / {{item.javaFieldName}} / {{item.javaFieldType}}
+                                                +btn-remove('tableRemove(backupItem, keysTbl, $index)', '"Remove key field"')
+                                            div(ng-show='tableEditing(keysTbl, $index)')
+                                                +table-db-field-edit('keysTbl', 'cur', '{{::keysTbl.focusId + $index}}', '$index')
+                                tfoot(ng-show='tableNewItemActive(keysTbl)')
+                                    tr
+                                        td
+                                            +table-db-field-edit('keysTbl', 'new', 'KeyField', '-1')
+                .settings-row(ng-init='valuesTbl={type: "table-db-fields", model: "valueFields", focusId: "ValueField", ui: "table-db-fields"}')
+                    +ignite-form-group(ng-form=valueFieldsForm ng-model=valueFields)
+                        ignite-form-field-label(id='valueFields')
+                            | Value fields
+                        ignite-form-group-tooltip
+                            | Collection of value fields descriptions for CacheJdbcPojoStore
+                        ignite-form-group-add(ng-click='tableNewItem(valuesTbl)')
+                            | Add value field
+                        .group-content-empty(ng-show='!((#{valueFields} && #{valueFields}.length > 0) || tableNewItemActive(valuesTbl))') Not defined
+                        .group-content(ng-show='(#{valueFields} && #{valueFields}.length > 0) || tableNewItemActive(valuesTbl)')
+                            table.links-edit(st-table=valueFields)
+                                tbody
+                                    tr(ng-repeat='item in #{valueFields}')
+                                        td
+                                            div(ng-show='!tableEditing(valuesTbl, $index)')
+                                                a.labelFormField(ng-click='tableStartEdit(backupItem, valuesTbl, $index)') {{$index + 1}}) {{item.databaseFieldName}} / {{item.databaseFieldType}} / {{item.javaFieldName}} / {{item.javaFieldType}}
+                                                +btn-remove('tableRemove(backupItem, valuesTbl, $index)', '"Remove key field"')
+                                            div(ng-show='tableEditing(valuesTbl, $index)')
+                                                +table-db-field-edit('valuesTbl', 'cur', '{{::valuesTbl.focusId + $index}}', '$index')
+                                tfoot(ng-show='tableNewItemActive(valuesTbl)')
+                                    tr
+                                        td
+                                            +table-db-field-edit('valuesTbl', 'new', 'ValueField', '-1')
+            .col-sm-6
+                +preview-xml-java(model, 'domainStore')
+

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/frontend/app/modules/states/configuration/igfs/dual.jade
----------------------------------------------------------------------
diff --git a/modules/web-console/frontend/app/modules/states/configuration/igfs/dual.jade b/modules/web-console/frontend/app/modules/states/configuration/igfs/dual.jade
new file mode 100644
index 0000000..1b3a00a
--- /dev/null
+++ b/modules/web-console/frontend/app/modules/states/configuration/igfs/dual.jade
@@ -0,0 +1,42 @@
+//-
+    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.jade
+
+-var form = 'dualMode'
+-var model = 'backupItem'
+
+.panel.panel-default(ng-form=form novalidate)
+    .panel-heading(bs-collapse-toggle='' ng-click='ui.loadPanel("#{form}")')
+        ignite-form-panel-chevron
+        label Dual mode
+        ignite-form-field-tooltip.tipLabel
+            | IGFS supports dual-mode that allows it to work as either a standalone file system in Hadoop cluster, or work in tandem with HDFS, providing a primary caching layer for the secondary HDFS#[br]
+            | As a caching layer it provides highly configurable read-through and write-through behaviour
+        ignite-form-revert
+    .panel-collapse(role='tabpanel' bs-collapse-target id=form)
+        .panel-body(ng-if='ui.isPanelLoaded("#{form}")')
+            .col-sm-6
+                .settings-row
+                    +number('Maximum pending puts size:', model + '.dualModeMaxPendingPutsSize', '"dualModeMaxPendingPutsSize"', 'true', '0', 'Number.MIN_SAFE_INTEGER',
+                        'Maximum amount of pending data read from the secondary file system and waiting to be written to data cache<br/>\
+                        Zero or negative value stands for unlimited size')
+                .settings-row
+                    +java-class('Put executor service:', model + '.dualModePutExecutorService', '"dualModePutExecutorService"', 'true', 'false', 'DUAL mode put operation executor service')
+                .settings-row
+                    +checkbox('Put executor service shutdown', model + '.dualModePutExecutorServiceShutdown', '"dualModePutExecutorServiceShutdown"', 'DUAL mode put operation executor service shutdown flag')
+            .col-sm-6
+                +preview-xml-java(model, 'igfsDualMode')

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/frontend/app/modules/states/configuration/igfs/fragmentizer.jade
----------------------------------------------------------------------
diff --git a/modules/web-console/frontend/app/modules/states/configuration/igfs/fragmentizer.jade b/modules/web-console/frontend/app/modules/states/configuration/igfs/fragmentizer.jade
new file mode 100644
index 0000000..edc2352
--- /dev/null
+++ b/modules/web-console/frontend/app/modules/states/configuration/igfs/fragmentizer.jade
@@ -0,0 +1,43 @@
+//-
+    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.jade
+
+-var form = 'fragmentizer'
+-var model = 'backupItem'
+
+.panel.panel-default(ng-form=form novalidate)
+    .panel-heading(bs-collapse-toggle='' ng-click='ui.loadPanel("#{form}")')
+        ignite-form-panel-chevron
+        label Fragmentizer
+        ignite-form-field-tooltip.tipLabel
+            | Fragmentizer settings
+        ignite-form-revert
+    .panel-collapse(role='tabpanel' bs-collapse-target id=form)
+        .panel-body(ng-if='ui.isPanelLoaded("#{form}")')
+            .col-sm-6
+                -var enabled = model + '.fragmentizerEnabled'
+
+                .settings-row
+                    +checkbox('Enabled', enabled, '"fragmentizerEnabled"', 'Fragmentizer enabled flag')
+                .settings-row
+                    +number('Concurrent files:', model + '.fragmentizerConcurrentFiles', '"fragmentizerConcurrentFiles"', enabled, '0', '0', 'Number of files to process concurrently by fragmentizer')
+                .settings-row
+                    +number('Throttling block length:', model + '.fragmentizerThrottlingBlockLength', '"fragmentizerThrottlingBlockLength"', enabled, '16777216', '1', 'Length of file chunk to transmit before throttling is delayed')
+                .settings-row
+                    +number('Throttling delay:', model + '.fragmentizerThrottlingDelay', '"fragmentizerThrottlingDelay"', enabled, '200', '0', 'Delay in milliseconds for which fragmentizer is paused')
+            .col-sm-6
+                +preview-xml-java(model, 'igfsFragmentizer')

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/frontend/app/modules/states/configuration/igfs/general.jade
----------------------------------------------------------------------
diff --git a/modules/web-console/frontend/app/modules/states/configuration/igfs/general.jade b/modules/web-console/frontend/app/modules/states/configuration/igfs/general.jade
new file mode 100644
index 0000000..b087120
--- /dev/null
+++ b/modules/web-console/frontend/app/modules/states/configuration/igfs/general.jade
@@ -0,0 +1,54 @@
+//-
+    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.jade
+
+-var form = 'general'
+-var model = 'backupItem'
+
+.panel.panel-default(ng-form=form novalidate)
+    .panel-heading(bs-collapse-toggle)
+        ignite-form-panel-chevron
+        label General
+        ignite-form-revert
+    .panel-collapse(role='tabpanel' bs-collapse-target id='general')
+        .panel-body
+            .col-sm-6
+                .settings-row
+                    +text('Name:', model + '.name', '"igfsName"', 'true', 'Input name', 'IGFS name')
+                .settings-row
+                    +clusters(model, 'Associate clusters with the current IGFS')
+                .settings-row
+                    +dropdown('IGFS mode:', model + '.defaultMode', '"defaultMode"', 'true', 'DUAL_ASYNC',
+                    '[\
+                        {value: "PRIMARY", label: "PRIMARY"},\
+                        {value: "PROXY", label: "PROXY"},\
+                        {value: "DUAL_SYNC", label: "DUAL_SYNC"},\
+                        {value: "DUAL_ASYNC", label: "DUAL_ASYNC"}\
+                    ]',
+                    'Mode to specify how IGFS interacts with Hadoop file system\
+                    <ul>\
+                        <li>PRIMARY - in this mode IGFS will not delegate to secondary Hadoop file system and will cache all the files in memory only</li>\
+                        <li>PROXY - in this mode IGFS will not cache any files in memory and will only pass them through to secondary file system</li>\
+                        <li>DUAL_SYNC - in this mode IGFS will cache files locally and also <b>synchronously</b> write them through to secondary file system</li>\
+                        <li>DUAL_ASYNC - in this mode IGFS will cache files locally and also <b> asynchronously </b> write them through to secondary file system</li>\
+                    </ul>')
+                .settings-row
+                    +number('Group size:', model + '.affinnityGroupSize', '"affinnityGroupSize"', 'true', '512', '1',
+                        'Size of the group in blocks<br/>\
+                        Required for construction of affinity mapper in IGFS data cache')
+            .col-sm-6
+                +preview-xml-java(model, 'igfsGeneral')

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/frontend/app/modules/states/configuration/igfs/ipc.jade
----------------------------------------------------------------------
diff --git a/modules/web-console/frontend/app/modules/states/configuration/igfs/ipc.jade b/modules/web-console/frontend/app/modules/states/configuration/igfs/ipc.jade
new file mode 100644
index 0000000..bb5e00b
--- /dev/null
+++ b/modules/web-console/frontend/app/modules/states/configuration/igfs/ipc.jade
@@ -0,0 +1,60 @@
+//-
+    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.jade
+
+-var form = 'ipc'
+-var model = 'backupItem'
+
+.panel.panel-default(ng-form=form novalidate)
+    .panel-heading(bs-collapse-toggle='' ng-click='ui.loadPanel("#{form}")')
+        ignite-form-panel-chevron
+        label IPC
+        ignite-form-field-tooltip.tipLabel
+            | IGFS Inter-process communication properties
+        ignite-form-revert
+    .panel-collapse(role='tabpanel' bs-collapse-target id=form)
+        .panel-body(ng-if='ui.isPanelLoaded("#{form}")')
+            .col-sm-6
+                -var ipcEndpointConfiguration = model + '.ipcEndpointConfiguration'
+                -var enabled = model + '.ipcEndpointEnabled'
+
+                .settings-row
+                    +checkbox('Enabled', enabled, '"ipcEndpointEnabled"', 'IPC endpoint enabled flag')
+                .settings-row
+                    +dropdown('Type:', ipcEndpointConfiguration + '.type', '"ipcEndpointConfigurationType"', enabled, 'TCP',
+                        '[\
+                            {value: "SHMEM", label: "SHMEM"},\
+                            {value: "TCP", label: "TCP"}\
+                        ]',
+                        'IPC endpoint type\
+                        <ul>\
+                            <li>SHMEM - shared memory endpoint</li>\
+                            <li>TCP - TCP endpoint</li>\
+                        </ul>')
+                .settings-row
+                    +text-ip-address('Host:', ipcEndpointConfiguration + '.host', '"ipcEndpointConfigurationHost"', enabled, '127.0.0.1', 'Host endpoint is bound to')
+                .settings-row
+                    +number-min-max('Port:', ipcEndpointConfiguration + '.port', '"ipcEndpointConfigurationPort"', enabled, '10500', '1', '65535', 'Port endpoint is bound to')
+                .settings-row
+                    +number('Memory size:', ipcEndpointConfiguration + '.memorySize', '"ipcEndpointConfigurationMemorySize"', enabled, '262144', '1', 'Shared memory size in bytes allocated for endpoint communication')
+                .settings-row
+                    +text-enabled('Token directory:', ipcEndpointConfiguration + '.tokenDirectoryPath', '"ipcEndpointConfigurationTokenDirectoryPath"', enabled, 'false', 'ipc/shmem', 'Directory where shared memory tokens are stored')
+                .settings-row
+                    +number('Thread count:', ipcEndpointConfiguration + '.threadCount', 'ipcEndpointConfigurationThreadCount', enabled, 'availableProcessors', '1',
+                        'Number of threads used by this endpoint to process incoming requests')
+            .col-sm-6
+                +preview-xml-java(model, 'igfsIPC')


[40/52] ignite git commit: Web Console beta-3.

Posted by ak...@apache.org.
http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/frontend/app/directives/bs-affix-update.directive.js
----------------------------------------------------------------------
diff --git a/modules/web-console/frontend/app/directives/bs-affix-update.directive.js b/modules/web-console/frontend/app/directives/bs-affix-update.directive.js
new file mode 100644
index 0000000..925722c
--- /dev/null
+++ b/modules/web-console/frontend/app/directives/bs-affix-update.directive.js
@@ -0,0 +1,34 @@
+/*
+ * 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';
+
+export default ['igniteBsAffixUpdate', ['$window', '$timeout', ($window, $timeout) => {
+    let update = null;
+
+    const link = ({$last}) => {
+        if ($last) {
+            update && $timeout.cancel(update);
+            update = $timeout(() => angular.element($window).triggerHandler('resize'), 1000);
+        }
+    };
+
+    return {
+        restrict: 'A',
+        link
+    };
+}]];

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/frontend/app/directives/centered/centered.css
----------------------------------------------------------------------
diff --git a/modules/web-console/frontend/app/directives/centered/centered.css b/modules/web-console/frontend/app/directives/centered/centered.css
new file mode 100644
index 0000000..694c1d2
--- /dev/null
+++ b/modules/web-console/frontend/app/directives/centered/centered.css
@@ -0,0 +1,37 @@
+/*
+ * 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.
+ */
+
+.center-container {
+    position: fixed;
+    top: 0;
+    left: 0;
+    height: 100%;
+    width: 100%;
+    display: table;
+    pointer-events: none;
+    z-index: 9999;
+}
+
+.centered {
+    display: table-cell;
+    vertical-align: middle;
+    text-align: center;
+}
+
+.centered > * {
+    pointer-events: auto;
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/frontend/app/directives/centered/centered.directive.js
----------------------------------------------------------------------
diff --git a/modules/web-console/frontend/app/directives/centered/centered.directive.js b/modules/web-console/frontend/app/directives/centered/centered.directive.js
new file mode 100644
index 0000000..4abd086
--- /dev/null
+++ b/modules/web-console/frontend/app/directives/centered/centered.directive.js
@@ -0,0 +1,26 @@
+/*
+ * 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 './centered.css';
+
+export default ['centered', [() => {
+    return {
+        restrict: 'E',
+        transclude: true,
+        template: '<div class="center-container"><div class="centered"><div ng-transclude></div></div></div>'
+    };
+}]];

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/frontend/app/directives/copy-to-clipboard.directive.js
----------------------------------------------------------------------
diff --git a/modules/web-console/frontend/app/directives/copy-to-clipboard.directive.js b/modules/web-console/frontend/app/directives/copy-to-clipboard.directive.js
new file mode 100644
index 0000000..ee2110e
--- /dev/null
+++ b/modules/web-console/frontend/app/directives/copy-to-clipboard.directive.js
@@ -0,0 +1,29 @@
+/*
+ * 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.
+ */
+
+// Directive for copy to clipboard.
+export default ['igniteCopyToClipboard', ['IgniteCopyToClipboard', (CopyToClipboard) => {
+    return {
+        restrict: 'A',
+        link(scope, element, attrs) {
+            element.bind('click', () => CopyToClipboard.copy(attrs.igniteCopyToClipboard));
+
+            if (!document.queryCommandSupported('copy'))
+                element.hide();
+        }
+    };
+}]];

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/frontend/app/directives/hide-on-state-change/hide-on-state-change.directive.js
----------------------------------------------------------------------
diff --git a/modules/web-console/frontend/app/directives/hide-on-state-change/hide-on-state-change.directive.js b/modules/web-console/frontend/app/directives/hide-on-state-change/hide-on-state-change.directive.js
new file mode 100644
index 0000000..98f1c57
--- /dev/null
+++ b/modules/web-console/frontend/app/directives/hide-on-state-change/hide-on-state-change.directive.js
@@ -0,0 +1,31 @@
+/*
+ * 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 ['hideOnStateChange', ['$timeout', ($timeout) => {
+    const link = (scope, element) => {
+        scope.$on('$stateChangeSuccess', () => {
+            $timeout(() => {
+                element.fadeOut('slow');
+            });
+        });
+    };
+
+    return {
+        restrict: 'AE',
+        link
+    };
+}]];

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/frontend/app/directives/information/information.directive.js
----------------------------------------------------------------------
diff --git a/modules/web-console/frontend/app/directives/information/information.directive.js b/modules/web-console/frontend/app/directives/information/information.directive.js
new file mode 100644
index 0000000..a9a2f8c
--- /dev/null
+++ b/modules/web-console/frontend/app/directives/information/information.directive.js
@@ -0,0 +1,30 @@
+/*
+ * 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 templateUrl from './information.jade';
+
+export default ['igniteInformation', [() => {
+    return {
+        scope: {
+            title: '@'
+        },
+        restrict: 'E',
+        templateUrl,
+        replace: true,
+        transclude: true
+    };
+}]];

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/frontend/app/directives/information/information.jade
----------------------------------------------------------------------
diff --git a/modules/web-console/frontend/app/directives/information/information.jade b/modules/web-console/frontend/app/directives/information/information.jade
new file mode 100644
index 0000000..b805d4a
--- /dev/null
+++ b/modules/web-console/frontend/app/directives/information/information.jade
@@ -0,0 +1,20 @@
+//-
+    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.
+
+.block-information
+    span.icon.fa.fa-info-circle(ng-if='title')
+    h3(ng-if='title') {{::title}}
+    div(ng-transclude='')

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/frontend/app/directives/information/information.scss
----------------------------------------------------------------------
diff --git a/modules/web-console/frontend/app/directives/information/information.scss b/modules/web-console/frontend/app/directives/information/information.scss
new file mode 100644
index 0000000..39f3c05
--- /dev/null
+++ b/modules/web-console/frontend/app/directives/information/information.scss
@@ -0,0 +1,56 @@
+/*
+ * 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-block-information: #fcfcfc;
+$ignite-block-information-border: #aab8c6;
+$ignite-block-information-icon: #4a6785;
+
+.block-information {
+    position: relative;
+
+    background: $ignite-block-information;
+
+    border-radius: 5px;
+    border: 1px solid $ignite-block-information-border;
+
+    margin: 20px 0;
+    padding: 10px 10px 0 30px;
+
+    > h3 {
+        font-weight: bold;
+        margin-bottom: 10px;
+    }
+
+    > .icon {
+        cursor: default;
+
+        color: $ignite-block-information-icon;
+
+        position: absolute;
+        top: 12px;
+        left: 10px;
+
+        font-size: 16px;
+
+        vertical-align: text-bottom
+    }
+
+    ul {
+        padding-left: 20px;
+    }
+}
+

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/frontend/app/directives/match.directive.js
----------------------------------------------------------------------
diff --git a/modules/web-console/frontend/app/directives/match.directive.js b/modules/web-console/frontend/app/directives/match.directive.js
new file mode 100644
index 0000000..3a45f6d
--- /dev/null
+++ b/modules/web-console/frontend/app/directives/match.directive.js
@@ -0,0 +1,27 @@
+/*
+ * 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.
+ */
+
+// Directive to enable validation to match specified value.
+export default ['igniteMatch', ['$parse', ($parse) => {
+    return {
+        require: 'ngModel',
+        link(scope, elem, attrs, ctrl) {
+            scope.$watch(() => $parse(attrs.igniteMatch)(scope) === ctrl.$modelValue,
+                (currentValue) => ctrl.$setValidity('mismatch', currentValue));
+        }
+    };
+}]];

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/frontend/app/directives/on-click-focus.directive.js
----------------------------------------------------------------------
diff --git a/modules/web-console/frontend/app/directives/on-click-focus.directive.js b/modules/web-console/frontend/app/directives/on-click-focus.directive.js
new file mode 100644
index 0000000..5c9ee88
--- /dev/null
+++ b/modules/web-console/frontend/app/directives/on-click-focus.directive.js
@@ -0,0 +1,26 @@
+/*
+ * 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.
+ */
+
+// Directive to describe element that should be focused on click.
+export default ['igniteOnClickFocus', ['IgniteFocus', (Focus) => {
+    return function(scope, elem, attrs) {
+        elem.on('click', () => Focus.move(attrs.igniteOnClickFocus));
+
+        // Removes bound events in the element itself when the scope is destroyed
+        scope.$on('$destroy', () => elem.off('click'));
+    };
+}]];

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/frontend/app/directives/on-enter-focus-move.directive.js
----------------------------------------------------------------------
diff --git a/modules/web-console/frontend/app/directives/on-enter-focus-move.directive.js b/modules/web-console/frontend/app/directives/on-enter-focus-move.directive.js
new file mode 100644
index 0000000..2dd2884
--- /dev/null
+++ b/modules/web-console/frontend/app/directives/on-enter-focus-move.directive.js
@@ -0,0 +1,29 @@
+/*
+ * 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.
+ */
+
+// Directive to move focus to specified element on ENTER key.
+export default ['igniteOnEnterFocusMove', ['IgniteFocus', (Focus) => {
+    return function(scope, elem, attrs) {
+        elem.on('keydown keypress', (event) => {
+            if (event.which === 13) {
+                event.preventDefault();
+
+                Focus.move(attrs.igniteOnEnterFocusMove);
+            }
+        });
+    };
+}]];

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/frontend/app/directives/on-enter.directive.js
----------------------------------------------------------------------
diff --git a/modules/web-console/frontend/app/directives/on-enter.directive.js b/modules/web-console/frontend/app/directives/on-enter.directive.js
new file mode 100644
index 0000000..459220e
--- /dev/null
+++ b/modules/web-console/frontend/app/directives/on-enter.directive.js
@@ -0,0 +1,32 @@
+/*
+ * 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.
+ */
+
+// Directive to bind ENTER key press with some user action.
+export default ['igniteOnEnter', ['$timeout', ($timeout) => {
+    return function(scope, elem, attrs) {
+        elem.on('keydown keypress', (event) => {
+            if (event.which === 13) {
+                scope.$apply(() => $timeout(() => scope.$eval(attrs.igniteOnEnter)));
+
+                event.preventDefault();
+            }
+        });
+
+        // Removes bound events in the element itself when the scope is destroyed.
+        scope.$on('$destroy', () => elem.off('keydown keypress'));
+    };
+}]];

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/frontend/app/directives/on-escape.directive.js
----------------------------------------------------------------------
diff --git a/modules/web-console/frontend/app/directives/on-escape.directive.js b/modules/web-console/frontend/app/directives/on-escape.directive.js
new file mode 100644
index 0000000..aa1accd
--- /dev/null
+++ b/modules/web-console/frontend/app/directives/on-escape.directive.js
@@ -0,0 +1,32 @@
+/*
+ * 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.
+ */
+
+// Directive to bind ESC key press with some user action.
+export default ['igniteOnEscape', ['$timeout', ($timeout) => {
+    return function(scope, elem, attrs) {
+        elem.on('keydown keypress', (event) => {
+            if (event.which === 27) {
+                scope.$apply(() => $timeout(() => scope.$eval(attrs.igniteOnEscape)));
+
+                event.preventDefault();
+            }
+        });
+
+        // Removes bound events in the element itself when the scope is destroyed.
+        scope.$on('$destroy', () => elem.off('keydown keypress'));
+    };
+}]];

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/frontend/app/directives/ui-ace-docker/ui-ace-docker.controller.js
----------------------------------------------------------------------
diff --git a/modules/web-console/frontend/app/directives/ui-ace-docker/ui-ace-docker.controller.js b/modules/web-console/frontend/app/directives/ui-ace-docker/ui-ace-docker.controller.js
new file mode 100644
index 0000000..32feaf3
--- /dev/null
+++ b/modules/web-console/frontend/app/directives/ui-ace-docker/ui-ace-docker.controller.js
@@ -0,0 +1,33 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+export default ['$scope', 'GeneratorDocker', function($scope, docker) {
+    const ctrl = this;
+
+    // Watchers definition.
+    const clusterWatcher = () => {
+        delete ctrl.data;
+
+        if (!$scope.cluster)
+            return;
+
+        ctrl.data = docker.generate($scope.cluster, 'latest');
+    };
+
+    // Setup watchers.
+    $scope.$watch('cluster', clusterWatcher);
+}];

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/frontend/app/directives/ui-ace-docker/ui-ace-docker.directive.js
----------------------------------------------------------------------
diff --git a/modules/web-console/frontend/app/directives/ui-ace-docker/ui-ace-docker.directive.js b/modules/web-console/frontend/app/directives/ui-ace-docker/ui-ace-docker.directive.js
new file mode 100644
index 0000000..08e4f76
--- /dev/null
+++ b/modules/web-console/frontend/app/directives/ui-ace-docker/ui-ace-docker.directive.js
@@ -0,0 +1,46 @@
+/*
+ * 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 templateUrl from './ui-ace-docker.jade';
+import controller from './ui-ace-docker.controller';
+
+export default ['igniteUiAceDocker', [() => {
+    const link = ($scope, $el, $attrs, [igniteUiAceTabs]) => {
+        if (igniteUiAceTabs.onLoad)
+            $scope.onLoad = igniteUiAceTabs.onLoad;
+
+        if (igniteUiAceTabs.onChange)
+            $scope.onChange = igniteUiAceTabs.onChange;
+    };
+
+    return {
+        restrict: 'E',
+        scope: {
+            cluster: '=',
+            data: '=ngModel'
+        },
+        bindToController: {
+            cluster: '=',
+            data: '=ngModel'
+        },
+        link,
+        templateUrl,
+        controller,
+        controllerAs: 'ctrl',
+        require: ['?^igniteUiAceTabs']
+    };
+}]];

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/frontend/app/directives/ui-ace-docker/ui-ace-docker.jade
----------------------------------------------------------------------
diff --git a/modules/web-console/frontend/app/directives/ui-ace-docker/ui-ace-docker.jade b/modules/web-console/frontend/app/directives/ui-ace-docker/ui-ace-docker.jade
new file mode 100644
index 0000000..3b0e7b8
--- /dev/null
+++ b/modules/web-console/frontend/app/directives/ui-ace-docker/ui-ace-docker.jade
@@ -0,0 +1,31 @@
+//-
+    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.
+
+mixin hard-link(ref, txt)
+    a(style='color:#ec1c24' href=ref target='_blank') #{txt}
+
+.panel-details-noborder
+    .details-row
+        p
+            +hard-link('https://docs.docker.com/reference/builder', 'Docker')
+            | &nbsp;file is a text file with instructions to create Docker image.<br/>
+            | To build image you have to store following Docker file with your Ignite XML configuration to the same directory.<br>
+            | Also you could use predefined&nbsp;
+            +hard-link('https://ignite.apache.org/download.html#docker', 'Apache Ignite docker image')
+            | . For more information about using Ignite with Docker please read&nbsp;
+            +hard-link('http://apacheignite.readme.io/docs/docker-deployment', 'documentation')
+            |.
+    .details-row(ng-if='ctrl.data' ignite-ace='{onLoad: onLoad, mode: "dockerfile"}' ng-model='ctrl.data')

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/frontend/app/directives/ui-ace-java/ui-ace-java.controller.js
----------------------------------------------------------------------
diff --git a/modules/web-console/frontend/app/directives/ui-ace-java/ui-ace-java.controller.js b/modules/web-console/frontend/app/directives/ui-ace-java/ui-ace-java.controller.js
new file mode 100644
index 0000000..f869e65
--- /dev/null
+++ b/modules/web-console/frontend/app/directives/ui-ace-java/ui-ace-java.controller.js
@@ -0,0 +1,32 @@
+/*
+ * 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 SERVER_CFG = 'ServerConfigurationFactory';
+const CLIENT_CFG = 'ClientConfigurationFactory';
+
+export default ['$scope', 'GeneratorJava', function($scope, generator) {
+    const ctrl = this;
+
+    delete ctrl.data;
+
+    // Set default generator
+    ctrl.generator = (cluster) => {
+        const type = $scope.cfg ? CLIENT_CFG : SERVER_CFG;
+
+        return generator.cluster(cluster, 'config', type, $scope.cfg);
+    };
+}];

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/frontend/app/directives/ui-ace-java/ui-ace-java.directive.js
----------------------------------------------------------------------
diff --git a/modules/web-console/frontend/app/directives/ui-ace-java/ui-ace-java.directive.js b/modules/web-console/frontend/app/directives/ui-ace-java/ui-ace-java.directive.js
new file mode 100644
index 0000000..fbb1431
--- /dev/null
+++ b/modules/web-console/frontend/app/directives/ui-ace-java/ui-ace-java.directive.js
@@ -0,0 +1,147 @@
+/*
+ * 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 templateUrl from './ui-ace-java.jade';
+import controller from './ui-ace-java.controller';
+
+export default ['igniteUiAceJava', ['GeneratorJava', (generator) => {
+    const link = (scope, $el, attrs, [ctrl, igniteUiAceTabs, formCtrl, ngModelCtrl]) => {
+        if (formCtrl && ngModelCtrl)
+            formCtrl.$removeControl(ngModelCtrl);
+
+        if (igniteUiAceTabs && igniteUiAceTabs.onLoad) {
+            scope.onLoad = (editor) => {
+                igniteUiAceTabs.onLoad(editor);
+
+                scope.$watch('master', () => editor.attractAttention = false);
+            };
+        }
+
+        if (igniteUiAceTabs && igniteUiAceTabs.onChange)
+            scope.onChange = igniteUiAceTabs.onChange;
+
+        const render = (data) => {
+            delete ctrl.data;
+
+            if (!data)
+                return;
+
+            return ctrl.generator(scope.master);
+        };
+
+        // Setup generator.
+        if (scope.generator) {
+            const method = scope.generator;
+
+            switch (method) {
+                case 'clusterCaches':
+                    ctrl.generator = (cluster) => {
+                        const caches = _.reduce(scope.detail, (acc, cache) => {
+                            if (_.includes(cluster.caches, cache.value))
+                                acc.push(cache.cache);
+
+                            return acc;
+                        }, []);
+
+                        return generator.clusterCaches(caches, null, true, generator.clusterGeneral(cluster)).asString();
+                    };
+
+                    break;
+
+                case 'igfss':
+                    ctrl.generator = (cluster) => {
+                        const igfss = _.reduce(scope.detail, (acc, igfs) => {
+                            if (_.includes(cluster.igfss, igfs.value))
+                                acc.push(igfs.igfs);
+
+                            return acc;
+                        }, []);
+
+                        return generator.igfss(igfss, 'cfg').asString();
+                    };
+
+                    break;
+
+                case 'cacheStore':
+                case 'cacheQuery':
+                    ctrl.generator = (cache) => {
+                        const domains = _.reduce(scope.detail, (acc, domain) => {
+                            if (_.includes(cache.domains, domain.value))
+                                acc.push(domain.meta);
+
+                            return acc;
+                        }, []);
+
+                        return generator[method](cache, domains).asString();
+                    };
+
+                    break;
+
+                case 'cacheNodeFilter':
+                    ctrl.generator = (cache) => {
+                        const igfss = _.reduce(scope.detail, (acc, igfs) => {
+                            acc.push(igfs.igfs);
+
+                            return acc;
+                        }, []);
+
+                        return generator.cacheNodeFilter(cache, igfss).asString();
+                    };
+
+                    break;
+
+                default:
+                    ctrl.generator = (data) => generator[method](data).asString();
+            }
+        }
+
+        if (!_.isUndefined(attrs.clusterCfg)) {
+            scope.$watch('cfg', (cfg) => {
+                if (!_.isUndefined(cfg))
+                    return;
+
+                scope.cfg = {};
+            });
+
+            scope.$watch('cfg', (data) => ctrl.data = render(data), true);
+        }
+
+        const noDeepWatch = !(typeof attrs.noDeepWatch !== 'undefined');
+
+        // Setup watchers.
+        scope.$watch('master', (data) => ctrl.data = render(data), noDeepWatch);
+    };
+
+    return {
+        priority: 1,
+        restrict: 'E',
+        scope: {
+            master: '=',
+            detail: '=',
+            generator: '@',
+            cfg: '=?clusterCfg'
+        },
+        bindToController: {
+            data: '=?ngModel'
+        },
+        link,
+        templateUrl,
+        controller,
+        controllerAs: 'ctrl',
+        require: ['igniteUiAceJava', '?^igniteUiAceTabs', '?^form', '?ngModel']
+    };
+}]];

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/frontend/app/directives/ui-ace-java/ui-ace-java.jade
----------------------------------------------------------------------
diff --git a/modules/web-console/frontend/app/directives/ui-ace-java/ui-ace-java.jade b/modules/web-console/frontend/app/directives/ui-ace-java/ui-ace-java.jade
new file mode 100644
index 0000000..5acffb8
--- /dev/null
+++ b/modules/web-console/frontend/app/directives/ui-ace-java/ui-ace-java.jade
@@ -0,0 +1,22 @@
+//-
+    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.
+
+div(ng-if='ctrl.data' 
+    ignite-ace='{onLoad: onLoad, \
+             onChange: onChange, \
+             renderOptions: renderOptions, \
+             mode: "java"}' 
+    ng-model='ctrl.data')

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/frontend/app/directives/ui-ace-pojos/ui-ace-pojos.controller.js
----------------------------------------------------------------------
diff --git a/modules/web-console/frontend/app/directives/ui-ace-pojos/ui-ace-pojos.controller.js b/modules/web-console/frontend/app/directives/ui-ace-pojos/ui-ace-pojos.controller.js
new file mode 100644
index 0000000..bc185b3
--- /dev/null
+++ b/modules/web-console/frontend/app/directives/ui-ace-pojos/ui-ace-pojos.controller.js
@@ -0,0 +1,95 @@
+/*
+ * 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 ['$scope', 'JavaTypes', 'GeneratorJava', function($scope, JavaTypes, generator) {
+    const ctrl = this;
+
+    // Watchers definition.
+    // Watcher clean instance data if instance to cluster caches was change
+    const cleanPojos = () => {
+        delete ctrl.class;
+        delete ctrl.pojos;
+        delete ctrl.classes;
+    };
+
+    // Watcher update pojos when changes caches and checkers useConstructor and includeKeyFields
+    const updatePojos = () => {
+        delete ctrl.pojos;
+
+        if (!ctrl.cluster || !ctrl.cluster.caches)
+            return;
+
+        ctrl.pojos = generator.pojos(ctrl.cluster.caches, ctrl.useConstructor, ctrl.includeKeyFields);
+    };
+
+    // Watcher update classes after
+    const updateClasses = (value) => {
+        delete ctrl.classes;
+
+        if (!value)
+            return;
+
+        const classes = ctrl.classes = [];
+
+        _.forEach(ctrl.pojos, (pojo) => {
+            if (pojo.keyType && JavaTypes.nonBuiltInClass(pojo.keyType))
+                classes.push(pojo.keyType);
+
+            classes.push(pojo.valueType);
+        });
+    };
+
+    // Update pojos class.
+    const updateClass = (value) => {
+        if (!value || !ctrl.pojos.length)
+            return;
+
+        const keyType = ctrl.pojos[0].keyType;
+
+        ctrl.class = ctrl.class || (JavaTypes.nonBuiltInClass(keyType) ? keyType : null) || ctrl.pojos[0].valueType;
+    };
+
+    // Update pojos data.
+    const updatePojosData = (value) => {
+        if (!value)
+            return;
+
+        _.forEach(ctrl.pojos, (pojo) => {
+            if (pojo.keyType === ctrl.class) {
+                ctrl.data = pojo.keyClass;
+
+                return false;
+            }
+
+            if (pojo.valueType === ctrl.class) {
+                ctrl.data = pojo.valueClass;
+
+                return false;
+            }
+        });
+    };
+
+    // Setup watchers. Watchers order is important.
+    $scope.$watch('ctrl.cluster.caches', cleanPojos);
+    $scope.$watch('ctrl.cluster.caches', updatePojos);
+    $scope.$watch('ctrl.cluster.caches', updateClasses);
+    $scope.$watch('ctrl.useConstructor', updatePojos);
+    $scope.$watch('ctrl.includeKeyFields', updatePojos);
+    $scope.$watch('ctrl.pojos', updateClass);
+    $scope.$watch('ctrl.pojos', updatePojosData);
+    $scope.$watch('ctrl.class', updatePojosData);
+}];

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/frontend/app/directives/ui-ace-pojos/ui-ace-pojos.directive.js
----------------------------------------------------------------------
diff --git a/modules/web-console/frontend/app/directives/ui-ace-pojos/ui-ace-pojos.directive.js b/modules/web-console/frontend/app/directives/ui-ace-pojos/ui-ace-pojos.directive.js
new file mode 100644
index 0000000..7c224b7
--- /dev/null
+++ b/modules/web-console/frontend/app/directives/ui-ace-pojos/ui-ace-pojos.directive.js
@@ -0,0 +1,46 @@
+/*
+ * 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 templateUrl from './ui-ace-pojos.jade';
+import controller from './ui-ace-pojos.controller';
+
+export default ['igniteUiAcePojos', [() => {
+    const link = ($scope, $el, $attrs, [igniteUiAceTabs]) => {
+        if (igniteUiAceTabs.onLoad)
+            $scope.onLoad = igniteUiAceTabs.onLoad;
+
+        if (igniteUiAceTabs.onChange)
+            $scope.onChange = igniteUiAceTabs.onChange;
+    };
+
+    return {
+        restrict: 'E',
+        scope: {
+            cluster: '=',
+            pojos: '=ngModel'
+        },
+        bindToController: {
+            cluster: '=',
+            pojos: '=ngModel'
+        },
+        link,
+        templateUrl,
+        controller,
+        controllerAs: 'ctrl',
+        require: ['?^igniteUiAceTabs']
+    };
+}]];

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/frontend/app/directives/ui-ace-pojos/ui-ace-pojos.jade
----------------------------------------------------------------------
diff --git a/modules/web-console/frontend/app/directives/ui-ace-pojos/ui-ace-pojos.jade b/modules/web-console/frontend/app/directives/ui-ace-pojos/ui-ace-pojos.jade
new file mode 100644
index 0000000..ed1432b
--- /dev/null
+++ b/modules/web-console/frontend/app/directives/ui-ace-pojos/ui-ace-pojos.jade
@@ -0,0 +1,40 @@
+//-
+    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.
+
+mixin check-tooltip(message)
+    i.tipLabel.fa.fa-question-circle(bs-tooltip='"#{message}"')
+
+.panel-details-noborder
+    .details-row
+        .col-xs-2.col-sm-2.col-md-2
+            label POJO class:
+        .col-xs-10.col-sm-10.col-md-10.summary-pojo-list
+            button.select-toggle.form-control(ng-model='ctrl.class' bs-select bs-options='item for item in ctrl.classes' data-container='')
+    .details-row.checkbox
+        .col-xs-2.col-sm-2.col-md-2
+        .col-xs-10.col-sm-10.col-md-10
+            label
+                input(type='checkbox' ng-model='ctrl.useConstructor')
+                | Generate constructors
+            +check-tooltip("Generate empty and full constructors in POJO classes")
+    .details-row.checkbox
+        .col-xs-2.col-sm-2.col-md-2
+        .col-xs-10.col-sm-10.col-md-10
+            label
+                input(type='checkbox' ng-model='ctrl.includeKeyFields')
+                | Include key fields
+            +check-tooltip("Generate key fields in POJO value class")
+    .details-row(ng-if='ctrl.data' ignite-ace='{onLoad: onLoad, mode: "java"}' ng-model='ctrl.data')

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/frontend/app/directives/ui-ace-pom/ui-ace-pom.controller.js
----------------------------------------------------------------------
diff --git a/modules/web-console/frontend/app/directives/ui-ace-pom/ui-ace-pom.controller.js b/modules/web-console/frontend/app/directives/ui-ace-pom/ui-ace-pom.controller.js
new file mode 100644
index 0000000..ec880bd
--- /dev/null
+++ b/modules/web-console/frontend/app/directives/ui-ace-pom/ui-ace-pom.controller.js
@@ -0,0 +1,33 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+export default ['$scope', 'GeneratorPom', 'IgniteVersion', function($scope, pom, IgniteVersion) {
+    const ctrl = this;
+
+    // Watchers definition.
+    const clusterWatcher = (value) => {
+        delete ctrl.data;
+
+        if (!value)
+            return;
+
+        ctrl.data = pom.generate($scope.cluster, IgniteVersion.version).asString();
+    };
+
+    // Setup watchers.
+    $scope.$watch('cluster', clusterWatcher);
+}];

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/frontend/app/directives/ui-ace-pom/ui-ace-pom.directive.js
----------------------------------------------------------------------
diff --git a/modules/web-console/frontend/app/directives/ui-ace-pom/ui-ace-pom.directive.js b/modules/web-console/frontend/app/directives/ui-ace-pom/ui-ace-pom.directive.js
new file mode 100644
index 0000000..2a7a878
--- /dev/null
+++ b/modules/web-console/frontend/app/directives/ui-ace-pom/ui-ace-pom.directive.js
@@ -0,0 +1,41 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import templateUrl from './ui-ace-pom.jade';
+import controller from './ui-ace-pom.controller';
+
+export default ['igniteUiAcePom', [() => {
+    const link = ($scope, $el, $attrs, [igniteUiAceTabs]) => {
+        if (igniteUiAceTabs.onLoad)
+            $scope.onLoad = igniteUiAceTabs.onLoad;
+
+        if (igniteUiAceTabs.onChange)
+            $scope.onChange = igniteUiAceTabs.onChange;
+    };
+
+    return {
+        restrict: 'E',
+        scope: {
+            cluster: '='
+        },
+        link,
+        templateUrl,
+        controller,
+        controllerAs: 'ctrl',
+        require: ['?^igniteUiAceTabs']
+    };
+}]];

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/frontend/app/directives/ui-ace-pom/ui-ace-pom.jade
----------------------------------------------------------------------
diff --git a/modules/web-console/frontend/app/directives/ui-ace-pom/ui-ace-pom.jade b/modules/web-console/frontend/app/directives/ui-ace-pom/ui-ace-pom.jade
new file mode 100644
index 0000000..b973a74
--- /dev/null
+++ b/modules/web-console/frontend/app/directives/ui-ace-pom/ui-ace-pom.jade
@@ -0,0 +1,17 @@
+//-
+    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.
+
+div(ng-if='ctrl.data' ignite-ace='{onLoad: onLoad, mode: "xml"}' ng-model='ctrl.data')

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/frontend/app/directives/ui-ace-tabs.directive.js
----------------------------------------------------------------------
diff --git a/modules/web-console/frontend/app/directives/ui-ace-tabs.directive.js b/modules/web-console/frontend/app/directives/ui-ace-tabs.directive.js
new file mode 100644
index 0000000..2b90a72
--- /dev/null
+++ b/modules/web-console/frontend/app/directives/ui-ace-tabs.directive.js
@@ -0,0 +1,24 @@
+/*
+ * 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 ['igniteUiAceTabs', [() => {
+    return {
+        scope: true,
+        restrict: 'AE',
+        controller: _.noop
+    };
+}]];

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/frontend/app/directives/ui-ace-xml/ui-ace-xml.controller.js
----------------------------------------------------------------------
diff --git a/modules/web-console/frontend/app/directives/ui-ace-xml/ui-ace-xml.controller.js b/modules/web-console/frontend/app/directives/ui-ace-xml/ui-ace-xml.controller.js
new file mode 100644
index 0000000..3233757
--- /dev/null
+++ b/modules/web-console/frontend/app/directives/ui-ace-xml/ui-ace-xml.controller.js
@@ -0,0 +1,27 @@
+/*
+ * 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 ['$scope', 'GeneratorXml', function($scope, generator) {
+    const ctrl = this;
+
+    delete ctrl.data;
+
+    // Set default generator
+    ctrl.generator = (cluster) => {
+        return generator.cluster(cluster, $scope.cfg);
+    };
+}];

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/frontend/app/directives/ui-ace-xml/ui-ace-xml.directive.js
----------------------------------------------------------------------
diff --git a/modules/web-console/frontend/app/directives/ui-ace-xml/ui-ace-xml.directive.js b/modules/web-console/frontend/app/directives/ui-ace-xml/ui-ace-xml.directive.js
new file mode 100644
index 0000000..3bd834f
--- /dev/null
+++ b/modules/web-console/frontend/app/directives/ui-ace-xml/ui-ace-xml.directive.js
@@ -0,0 +1,147 @@
+/*
+ * 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 templateUrl from './ui-ace-xml.jade';
+import controller from './ui-ace-xml.controller';
+
+export default ['igniteUiAceXml', ['GeneratorXml', (generator) => {
+    const link = (scope, $el, attrs, [ctrl, igniteUiAceTabs, formCtrl, ngModelCtrl]) => {
+        if (formCtrl && ngModelCtrl)
+            formCtrl.$removeControl(ngModelCtrl);
+
+        if (igniteUiAceTabs && igniteUiAceTabs.onLoad) {
+            scope.onLoad = (editor) => {
+                igniteUiAceTabs.onLoad(editor);
+
+                scope.$watch('master', () => editor.attractAttention = false);
+            };
+        }
+
+        if (igniteUiAceTabs && igniteUiAceTabs.onChange)
+            scope.onChange = igniteUiAceTabs.onChange;
+
+        const render = (data) => {
+            delete ctrl.data;
+
+            if (!data)
+                return;
+
+            return ctrl.generator(scope.master);
+        };
+
+        // Setup generator.
+        if (scope.generator) {
+            const method = scope.generator;
+
+            switch (method) {
+                case 'clusterCaches':
+                    ctrl.generator = (cluster) => {
+                        const caches = _.reduce(scope.detail, (acc, cache) => {
+                            if (_.includes(cluster.caches, cache.value))
+                                acc.push(cache.cache);
+
+                            return acc;
+                        }, []);
+
+                        return generator.clusterCaches(caches, null, true, generator.clusterGeneral(cluster)).asString();
+                    };
+
+                    break;
+
+                case 'igfss':
+                    ctrl.generator = (cluster) => {
+                        const igfss = _.reduce(scope.detail, (acc, igfs) => {
+                            if (_.includes(cluster.igfss, igfs.value))
+                                acc.push(igfs.igfs);
+
+                            return acc;
+                        }, []);
+
+                        return generator.igfss(igfss).asString();
+                    };
+
+                    break;
+
+                case 'cacheStore':
+                case 'cacheQuery':
+                    ctrl.generator = (cache) => {
+                        const domains = _.reduce(scope.detail, (acc, domain) => {
+                            if (_.includes(cache.domains, domain.value))
+                                acc.push(domain.meta);
+
+                            return acc;
+                        }, []);
+
+                        return generator[method](cache, domains).asString();
+                    };
+
+                    break;
+
+                case 'cacheNodeFilter':
+                    ctrl.generator = (cache) => {
+                        const igfss = _.reduce(scope.detail, (acc, igfs) => {
+                            acc.push(igfs.igfs);
+
+                            return acc;
+                        }, []);
+
+                        return generator.cacheNodeFilter(cache, igfss).asString();
+                    };
+
+                    break;
+
+                default:
+                    ctrl.generator = (data) => generator[method](data).asString();
+            }
+        }
+
+        if (!_.isUndefined(attrs.clusterCfg)) {
+            scope.$watch('cfg', (cfg) => {
+                if (!_.isUndefined(cfg))
+                    return;
+
+                scope.cfg = {};
+            });
+
+            scope.$watch('cfg', (data) => ctrl.data = render(data), true);
+        }
+
+        const noDeepWatch = !(typeof attrs.noDeepWatch !== 'undefined');
+
+        // Setup watchers.
+        scope.$watch('master', (data) => ctrl.data = render(data), noDeepWatch);
+    };
+
+    return {
+        priority: 1,
+        restrict: 'E',
+        scope: {
+            master: '=',
+            detail: '=',
+            generator: '@',
+            cfg: '=?clusterCfg'
+        },
+        bindToController: {
+            data: '=?ngModel'
+        },
+        link,
+        templateUrl,
+        controller,
+        controllerAs: 'ctrl',
+        require: ['igniteUiAceXml', '?^igniteUiAceTabs', '?^form', '?ngModel']
+    };
+}]];

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/frontend/app/directives/ui-ace-xml/ui-ace-xml.jade
----------------------------------------------------------------------
diff --git a/modules/web-console/frontend/app/directives/ui-ace-xml/ui-ace-xml.jade b/modules/web-console/frontend/app/directives/ui-ace-xml/ui-ace-xml.jade
new file mode 100644
index 0000000..0dd627a
--- /dev/null
+++ b/modules/web-console/frontend/app/directives/ui-ace-xml/ui-ace-xml.jade
@@ -0,0 +1,17 @@
+//-
+    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.
+
+div(ng-if='ctrl.data' ignite-ace='{onLoad: onLoad, onChange: onChange, mode: "xml"}' ng-model='ctrl.data')

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/frontend/app/filters/byName.filter.js
----------------------------------------------------------------------
diff --git a/modules/web-console/frontend/app/filters/byName.filter.js b/modules/web-console/frontend/app/filters/byName.filter.js
new file mode 100644
index 0000000..3b0746f
--- /dev/null
+++ b/modules/web-console/frontend/app/filters/byName.filter.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.
+ */
+
+export default ['byName', [() => (arr, search) => {
+    if (!(arr && arr.length) || !search)
+        return arr;
+
+    return _.filter(arr, ({ name }) => name.indexOf(search) >= 0);
+}]];

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/frontend/app/filters/domainsValidation.filter.js
----------------------------------------------------------------------
diff --git a/modules/web-console/frontend/app/filters/domainsValidation.filter.js b/modules/web-console/frontend/app/filters/domainsValidation.filter.js
new file mode 100644
index 0000000..1a38392
--- /dev/null
+++ b/modules/web-console/frontend/app/filters/domainsValidation.filter.js
@@ -0,0 +1,33 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+// Filter domain models with key fields configuration.
+export default ['domainsValidation', ['IgniteLegacyUtils', (LegacyUtils) => (domains, valid, invalid) => {
+    if (valid && invalid)
+        return domains;
+
+    const out = [];
+
+    _.forEach(domains, function(domain) {
+        const _valid = !LegacyUtils.domainForStoreConfigured(domain) || LegacyUtils.isJavaBuiltInClass(domain.keyType) || !_.isEmpty(domain.keyFields);
+
+        if (valid && _valid || invalid && !_valid)
+            out.push(domain);
+    });
+
+    return out;
+}]];

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/frontend/app/filters/duration.filter.js
----------------------------------------------------------------------
diff --git a/modules/web-console/frontend/app/filters/duration.filter.js b/modules/web-console/frontend/app/filters/duration.filter.js
new file mode 100644
index 0000000..deeedd7
--- /dev/null
+++ b/modules/web-console/frontend/app/filters/duration.filter.js
@@ -0,0 +1,38 @@
+/*
+ * 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 ['duration', [() => {
+    /**
+     * @param {Number} t Time in ms.
+     */
+    return (t) => {
+        const a = (i, suffix) => i && i !== '00' ? i + suffix + ' ' : '';
+
+        const cd = 24 * 60 * 60 * 1000;
+        const ch = 60 * 60 * 1000;
+        const cm = 60 * 1000;
+        const cs = 1000;
+
+        const d = Math.floor(t / cd);
+        const h = Math.floor((t - d * cd) / ch);
+        const m = Math.floor((t - d * cd - h * ch) / cm);
+        const s = Math.floor((t - d * cd - h * ch - m * cm) / cs);
+        const ms = t % 1000;
+
+        return a(d, 'd') + a(h, 'h') + a(m, 'm') + a(s, 's') + (t < cm ? ms + 'ms' : '');
+    };
+}]];

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/frontend/app/filters/hasPojo.filter.js
----------------------------------------------------------------------
diff --git a/modules/web-console/frontend/app/filters/hasPojo.filter.js b/modules/web-console/frontend/app/filters/hasPojo.filter.js
new file mode 100644
index 0000000..a179423
--- /dev/null
+++ b/modules/web-console/frontend/app/filters/hasPojo.filter.js
@@ -0,0 +1,18 @@
+/*
+ * 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 ['hasPojo', [() => ({caches} = []) => _.find(caches, (cache) => cache.domains && cache.domains.length)]];

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/frontend/app/helpers/jade/form.jade
----------------------------------------------------------------------
diff --git a/modules/web-console/frontend/app/helpers/jade/form.jade b/modules/web-console/frontend/app/helpers/jade/form.jade
new file mode 100644
index 0000000..4b017ea
--- /dev/null
+++ b/modules/web-console/frontend/app/helpers/jade/form.jade
@@ -0,0 +1,27 @@
+//-
+    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 ./form/form-field-feedback.jade
+include ./form/form-field-label.jade
+include ./form/form-field-text.jade
+include ./form/form-field-dropdown.jade
+include ./form/form-field-datalist.jade
+include ./form/form-field-checkbox.jade
+include ./form/form-field-number.jade
+include ./form/form-field-up.jade
+include ./form/form-field-down.jade
+
+include ./form/form-group.jade

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/frontend/app/helpers/jade/form/form-field-checkbox.jade
----------------------------------------------------------------------
diff --git a/modules/web-console/frontend/app/helpers/jade/form/form-field-checkbox.jade b/modules/web-console/frontend/app/helpers/jade/form/form-field-checkbox.jade
new file mode 100644
index 0000000..ef5cb37
--- /dev/null
+++ b/modules/web-console/frontend/app/helpers/jade/form/form-field-checkbox.jade
@@ -0,0 +1,38 @@
+//-
+    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.
+
+mixin form-field-checkbox(label, model, name, disabled, required, tip)
+    div.checkbox.col-xs-12.col-sm-12.col-md-12
+        label(id='{{ #{name} }}Label')
+            .input-tip
+                if block
+                    block
+                else
+                    input(
+                        id='{{ #{name} }}Input'
+                        name='{{ #{name} }}'
+                        type='checkbox'
+
+                        data-ng-model=model
+                        data-ng-required=required && '#{required}'
+                        data-ng-disabled=disabled && '#{disabled}'
+
+                        data-ng-focus='tableReset()'
+
+                        data-ignite-form-panel-field=''
+                    )
+            span #{label}
+            i.tipLabel.fa.fa-question-circle(bs-tooltip='' data-title=tip)

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/frontend/app/helpers/jade/form/form-field-datalist.jade
----------------------------------------------------------------------
diff --git a/modules/web-console/frontend/app/helpers/jade/form/form-field-datalist.jade b/modules/web-console/frontend/app/helpers/jade/form/form-field-datalist.jade
new file mode 100644
index 0000000..98a0b9a
--- /dev/null
+++ b/modules/web-console/frontend/app/helpers/jade/form/form-field-datalist.jade
@@ -0,0 +1,51 @@
+//-
+    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.
+
+mixin form-field-datalist(label, model, name, disabled, required, placeholder, options, tip)
+    -var errLbl = label.substring(0, label.length - 1)
+
+    mixin form-field-input()
+        input.form-control(
+            id='{{ #{name} }}Input'
+            name='{{ #{name} }}'
+            placeholder=placeholder
+           
+            data-ng-model=model
+
+            data-ng-required=required && '#{required}'
+            data-ng-disabled=disabled && '#{disabled}' || '!#{options}.length'
+
+            bs-typeahead
+            bs-options='item for item in #{options}'
+            container='body'
+            data-min-length='1'
+            ignite-retain-selection
+
+            data-ignite-form-panel-field=''
+        )&attributes(attributes.attributes)
+
+    div
+        +ignite-form-field-label(label, name, required)
+        .col-xs-8.col-sm-8.col-md-8
+            i.tipField.fa.fa-question-circle(bs-tooltip data-title=tip)
+
+            +form-field-feedback(name, 'required', errLbl + ' could not be empty!')
+
+            if block
+                block
+
+            .input-tip
+                +form-field-input(attributes=attributes)

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/frontend/app/helpers/jade/form/form-field-down.jade
----------------------------------------------------------------------
diff --git a/modules/web-console/frontend/app/helpers/jade/form/form-field-down.jade b/modules/web-console/frontend/app/helpers/jade/form/form-field-down.jade
new file mode 100644
index 0000000..cd10ebe
--- /dev/null
+++ b/modules/web-console/frontend/app/helpers/jade/form/form-field-down.jade
@@ -0,0 +1,18 @@
+//-
+    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.
+
+mixin ignite-form-field-down()
+    i.tipField.fa.fa-arrow-down(ignite-form-field-down ng-click="$ctrl.down()")&attributes(attributes)

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/frontend/app/helpers/jade/form/form-field-dropdown.jade
----------------------------------------------------------------------
diff --git a/modules/web-console/frontend/app/helpers/jade/form/form-field-dropdown.jade b/modules/web-console/frontend/app/helpers/jade/form/form-field-dropdown.jade
new file mode 100644
index 0000000..a8496bc
--- /dev/null
+++ b/modules/web-console/frontend/app/helpers/jade/form/form-field-dropdown.jade
@@ -0,0 +1,50 @@
+//-
+    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.
+
+mixin ignite-form-field-dropdown(label, model, name, disabled, required, multiple, placeholder, placeholderEmpty, options, tip)
+    mixin form-field-input()
+        button.select-toggle.form-control(
+            id='{{ #{name} }}Input'
+            name='{{ #{name} }}'
+
+            data-placeholder=placeholderEmpty ? '{{ #{options}.length > 0 ? "#{placeholder}" : "#{placeholderEmpty}" }}' : placeholder
+            
+            data-ng-model=model
+
+            data-ng-required=required && '#{required}'
+            data-ng-disabled=disabled && '#{disabled}' || '!#{options}.length'
+
+            bs-select
+            bs-options='item.value as item.label for item in #{options}' 
+
+            data-multiple=multiple ? '1' : false
+            data-container='body > .wrapper'
+
+            tabindex='0'
+
+            data-ignite-form-panel-field=''
+        )&attributes(attributes.attributes)
+
+    div
+        +ignite-form-field-label(label, name, required)
+        .col-xs-8.col-sm-8.col-md-8
+            i.tipField.fa.fa-question-circle(bs-tooltip data-title=tip)
+
+            if block
+                block
+
+            .input-tip
+                +form-field-input(attributes=attributes)

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/frontend/app/helpers/jade/form/form-field-feedback.jade
----------------------------------------------------------------------
diff --git a/modules/web-console/frontend/app/helpers/jade/form/form-field-feedback.jade b/modules/web-console/frontend/app/helpers/jade/form/form-field-feedback.jade
new file mode 100644
index 0000000..bf012db
--- /dev/null
+++ b/modules/web-console/frontend/app/helpers/jade/form/form-field-feedback.jade
@@ -0,0 +1,29 @@
+//-
+    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.
+
+mixin form-field-feedback(name, error, message)
+    -var __field = form + '[' + name + ']'
+    -var __error = __field + '.$error.' + error
+    -var __pristine = __field + '.$pristine'
+
+    i.fa.fa-exclamation-triangle.form-field-feedback(
+        ng-if='!#{__pristine} && #{__error}'
+        bs-tooltip
+        data-title=message
+        ignite-error=error
+        ignite-error-message=message
+        name='{{ #{name} }}'
+    )

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/frontend/app/helpers/jade/form/form-field-label.jade
----------------------------------------------------------------------
diff --git a/modules/web-console/frontend/app/helpers/jade/form/form-field-label.jade b/modules/web-console/frontend/app/helpers/jade/form/form-field-label.jade
new file mode 100644
index 0000000..cd5f8fc
--- /dev/null
+++ b/modules/web-console/frontend/app/helpers/jade/form/form-field-label.jade
@@ -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.
+
+mixin ignite-form-field-label(label, name, required)
+    label.col-xs-4.col-sm-4.col-md-4(
+        id='{{ #{name} }}Label'
+        for='{{ #{name} }}Input'
+        class="{{ #{required} ? 'required' : '' }}"
+    )
+        span !{label}

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/frontend/app/helpers/jade/form/form-field-number.jade
----------------------------------------------------------------------
diff --git a/modules/web-console/frontend/app/helpers/jade/form/form-field-number.jade b/modules/web-console/frontend/app/helpers/jade/form/form-field-number.jade
new file mode 100644
index 0000000..c32d3d9
--- /dev/null
+++ b/modules/web-console/frontend/app/helpers/jade/form/form-field-number.jade
@@ -0,0 +1,52 @@
+//-
+    Licensed to the Apache Software Foundation (ASF) under one or more
+    contributor license agreements.  See the NOTICE file distributed with
+    this work for additional information regarding copyright ownership.
+    The ASF licenses this file to You under the Apache License, Version 2.0
+    (the "License"); you may not use this file except in compliance with
+    the License.  You may obtain a copy of the License at
+
+         http://www.apache.org/licenses/LICENSE-2.0
+
+    Unless required by applicable law or agreed to in writing, software
+    distributed under the License is distributed on an "AS IS" BASIS,
+    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    See the License for the specific language governing permissions and
+    limitations under the License.
+
+mixin ignite-form-field-number(label, model, name, disabled, required, placeholder, min, max, step, tip)
+    mixin form-field-input()
+        input.form-control(
+            id='{{ #{name} }}Input'
+            name='{{ #{name} }}'
+            placeholder=placeholder
+            type='number'
+
+            min=min ? min : '0'
+            max=max ? max : '{{ Number.MAX_VALUE }}'
+            step=step ? step : '1'
+
+            data-ng-model=model
+
+            data-ng-required=required && '#{required}'
+            data-ng-disabled=disabled && '#{disabled}'
+            data-ng-focus='tableReset()'
+
+            data-ignite-form-panel-field=''
+        )&attributes(attributes.attributes)
+
+    div
+        +ignite-form-field-label(label, name, required)
+        .col-xs-8.col-sm-8.col-md-8
+            i.tipField.fa.fa-question-circle(bs-tooltip data-title=tip)
+            
+            +form-field-feedback(name, 'required', 'This field could not be empty')
+            +form-field-feedback(name, 'min', 'Value is less than allowable minimum: '+ min || 0)
+            +form-field-feedback(name, 'max', 'Value is more than allowable maximum: '+ max)
+            +form-field-feedback(name, 'number', 'Only numbers allowed')
+
+            if block
+                block
+
+            .input-tip
+                +form-field-input(attributes=attributes)

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/frontend/app/helpers/jade/form/form-field-text.jade
----------------------------------------------------------------------
diff --git a/modules/web-console/frontend/app/helpers/jade/form/form-field-text.jade b/modules/web-console/frontend/app/helpers/jade/form/form-field-text.jade
new file mode 100644
index 0000000..796e641
--- /dev/null
+++ b/modules/web-console/frontend/app/helpers/jade/form/form-field-text.jade
@@ -0,0 +1,47 @@
+//-
+    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.
+
+mixin ignite-form-field-input(name, model, disabled, required, placeholder)
+    input.form-control(
+        id='{{ #{name} }}Input'
+        name='{{ #{name} }}'
+        placeholder=placeholder
+        type='text'
+
+        data-ng-model=model
+
+        data-ng-required=required && '#{required}'
+        data-ng-disabled=disabled && '#{disabled}'
+        data-ng-focus='tableReset()'
+
+        data-ignite-form-panel-field=''
+    )&attributes(attributes ? attributes.attributes ? attributes.attributes : attributes : {})
+
+mixin ignite-form-field-text(label, model, name, disabled, required, placeholder, tip)
+    -var errLbl = label.substring(0, label.length - 1)
+
+    div
+        +ignite-form-field-label(label, name, required)
+        .col-xs-8.col-sm-8.col-md-8
+            i.tipField.fa.fa-question-circle(bs-tooltip data-title=tip)
+            
+            if block
+                block
+
+            +form-field-feedback(name, 'required', errLbl + ' could not be empty!')
+
+            .input-tip
+                +ignite-form-field-input(name, model, disabled, required, placeholder)(attributes=attributes)

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/frontend/app/helpers/jade/form/form-field-up.jade
----------------------------------------------------------------------
diff --git a/modules/web-console/frontend/app/helpers/jade/form/form-field-up.jade b/modules/web-console/frontend/app/helpers/jade/form/form-field-up.jade
new file mode 100644
index 0000000..c66cd0e
--- /dev/null
+++ b/modules/web-console/frontend/app/helpers/jade/form/form-field-up.jade
@@ -0,0 +1,18 @@
+//-
+    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.
+
+mixin ignite-form-field-up()
+    i.tipField.fa.fa-arrow-up.ng-scope(ignite-form-field-up ng-click="$ctrl.up()")&attributes(attributes)


[07/52] ignite git commit: Web Console beta-3.

Posted by ak...@apache.org.
http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/src/main/js/gulpfile.babel.js/tasks/build.js
----------------------------------------------------------------------
diff --git a/modules/web-console/src/main/js/gulpfile.babel.js/tasks/build.js b/modules/web-console/src/main/js/gulpfile.babel.js/tasks/build.js
deleted file mode 100644
index 7d7401b..0000000
--- a/modules/web-console/src/main/js/gulpfile.babel.js/tasks/build.js
+++ /dev/null
@@ -1,21 +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 gulp from 'gulp';
-import sequence from 'gulp-sequence';
-
-gulp.task('build', (cb) => sequence(['clean', 'clean:ignite-modules-temp'], 'ignite:modules', ['copy:resource', 'jade'], 'bundle', cb));

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/src/main/js/gulpfile.babel.js/tasks/bundle.js
----------------------------------------------------------------------
diff --git a/modules/web-console/src/main/js/gulpfile.babel.js/tasks/bundle.js b/modules/web-console/src/main/js/gulpfile.babel.js/tasks/bundle.js
deleted file mode 100644
index d3e8dca..0000000
--- a/modules/web-console/src/main/js/gulpfile.babel.js/tasks/bundle.js
+++ /dev/null
@@ -1,32 +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 gulp from 'gulp';
-import webpack from 'webpack';
-import webpackConfig from '../webpack';
-import WebpackDevServer from 'webpack-dev-server';
-
-gulp.task('bundle', (cb) => {
-    if (process.env.NODE_ENV === 'development') {
-        // Important! Call webpack and WebpackDevServer must be inline.
-        new WebpackDevServer(webpack(webpackConfig), webpackConfig.devServer)
-            .listen(webpackConfig.devServer.port, 'localhost', cb);
-    }
-    else
-        webpack(webpackConfig, cb);
-});
-

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/src/main/js/gulpfile.babel.js/tasks/clean.js
----------------------------------------------------------------------
diff --git a/modules/web-console/src/main/js/gulpfile.babel.js/tasks/clean.js b/modules/web-console/src/main/js/gulpfile.babel.js/tasks/clean.js
deleted file mode 100644
index c9104b2..0000000
--- a/modules/web-console/src/main/js/gulpfile.babel.js/tasks/clean.js
+++ /dev/null
@@ -1,32 +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 gulp from 'gulp';
-import clean from 'gulp-rimraf';
-
-import { destDir, igniteModulesTemp } from '../paths';
-
-// Clean build folder, remove files.
-gulp.task('clean', () =>
-    gulp.src(`${destDir}/*`, {read: false})
-        .pipe(clean({ force: true }))
-);
-
-gulp.task('clean:ignite-modules-temp', () =>
-    gulp.src(igniteModulesTemp, {read: false})
-        .pipe(clean({ force: true }))
-);

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/src/main/js/gulpfile.babel.js/tasks/copy.js
----------------------------------------------------------------------
diff --git a/modules/web-console/src/main/js/gulpfile.babel.js/tasks/copy.js b/modules/web-console/src/main/js/gulpfile.babel.js/tasks/copy.js
deleted file mode 100644
index 59373a8..0000000
--- a/modules/web-console/src/main/js/gulpfile.babel.js/tasks/copy.js
+++ /dev/null
@@ -1,33 +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 gulp from 'gulp';
-import sequence from 'gulp-sequence';
-
-import { destDir, resourcePaths, resourceModulePaths } from '../paths';
-
-gulp.task('copy:resource', (cb) => sequence('copy:resource:app', 'copy:resource:ignite_modules', cb));
-
-gulp.task('copy:resource:app', () =>
-    gulp.src(resourcePaths)
-        .pipe(gulp.dest(destDir))
-);
-
-gulp.task('copy:resource:ignite_modules', () =>
-    gulp.src(resourceModulePaths)
-        .pipe(gulp.dest(`${destDir}/ignite_modules`))
-);

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/src/main/js/gulpfile.babel.js/tasks/ignite-modules.js
----------------------------------------------------------------------
diff --git a/modules/web-console/src/main/js/gulpfile.babel.js/tasks/ignite-modules.js b/modules/web-console/src/main/js/gulpfile.babel.js/tasks/ignite-modules.js
deleted file mode 100644
index b97de7c..0000000
--- a/modules/web-console/src/main/js/gulpfile.babel.js/tasks/ignite-modules.js
+++ /dev/null
@@ -1,55 +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 gulp from 'gulp';
-import inject from 'gulp-inject';
-import clean from 'gulp-rimraf';
-import sequence from 'gulp-sequence';
-import {appModulePaths, igniteModulesTemp} from '../paths';
-
-gulp.task('ignite:modules', (cb) => sequence('ignite:modules:copy', 'ignite:modules:inject', cb));
-
-gulp.task('ignite:modules:copy', () =>
-    gulp.src(appModulePaths)
-        .pipe(gulp.dest(igniteModulesTemp))
-);
-
-gulp.task('ignite:modules:inject', () =>
-    gulp.src(`${igniteModulesTemp}/index.js`)
-        .pipe(inject(gulp.src([`${igniteModulesTemp}/**/main.js`]), {
-            starttag: '/* ignite:modules */',
-            endtag: '/* endignite */',
-            transform: (filePath) => {
-                const igniteModuleName = filePath.replace(/.*ignite_modules_temp\/([^\/]+).*/mgi, '$1');
-
-                // Return file contents as string.
-                return `import './${igniteModuleName}/main';`;
-            }
-        }))
-        .pipe(inject(gulp.src([`${igniteModulesTemp}/**/main.js`]), {
-            starttag: '/* ignite-console:modules */',
-            endtag: '/* endignite */',
-            transform: (filePath, file, i) => {
-                const igniteModuleName = filePath.replace(/.*ignite_modules_temp\/([^\/]+).*/mgi, '$1');
-
-                // Return file contents as string.
-                return (i ? ',' : '') + `'ignite-console.${igniteModuleName}'`;
-            }
-        }))
-        .pipe(clean({force: true}))
-        .pipe(gulp.dest(igniteModulesTemp))
-);

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/src/main/js/gulpfile.babel.js/tasks/jade.js
----------------------------------------------------------------------
diff --git a/modules/web-console/src/main/js/gulpfile.babel.js/tasks/jade.js b/modules/web-console/src/main/js/gulpfile.babel.js/tasks/jade.js
deleted file mode 100644
index b150373..0000000
--- a/modules/web-console/src/main/js/gulpfile.babel.js/tasks/jade.js
+++ /dev/null
@@ -1,40 +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 gulp from 'gulp';
-import jade from 'gulp-jade';
-import sequence from 'gulp-sequence';
-
-import { jadePaths, jadeModulePaths, destDir } from '../paths';
-
-const jadeOptions = {
-    basedir: './'
-};
-
-gulp.task('jade', (cb) => sequence('jade:source', 'jade:ignite_modules', cb));
-
-gulp.task('jade:source', () =>
-    gulp.src(jadePaths)
-        .pipe(jade(jadeOptions))
-        .pipe(gulp.dest(destDir))
-);
-
-gulp.task('jade:ignite_modules', () =>
-    gulp.src(jadeModulePaths)
-        .pipe(jade(jadeOptions))
-        .pipe(gulp.dest(`${destDir}/ignite_modules`))
-);

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/src/main/js/gulpfile.babel.js/tasks/watch.js
----------------------------------------------------------------------
diff --git a/modules/web-console/src/main/js/gulpfile.babel.js/tasks/watch.js b/modules/web-console/src/main/js/gulpfile.babel.js/tasks/watch.js
deleted file mode 100644
index c179f9c..0000000
--- a/modules/web-console/src/main/js/gulpfile.babel.js/tasks/watch.js
+++ /dev/null
@@ -1,31 +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 gulp from 'gulp';
-import sequence from 'gulp-sequence';
-
-import { jadePaths, jadeModulePaths, resourcePaths, resourceModulePaths, appModulePaths } from '../paths';
-
-gulp.task('watch:ignite-modules', (cb) => sequence('clean:ignite-modules-temp', 'ignite:modules', cb));
-
-// Build + watch task.
-gulp.task('watch', ['build'], () => {
-    gulp.watch(jadePaths.concat(jadeModulePaths), ['jade']);
-    gulp.watch(resourcePaths, ['copy:resource:app']);
-    gulp.watch(resourceModulePaths, ['copy:resource:ignite_modules']);
-    gulp.watch(appModulePaths, ['watch:ignite-modules']);
-});

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/src/main/js/gulpfile.babel.js/webpack/common.js
----------------------------------------------------------------------
diff --git a/modules/web-console/src/main/js/gulpfile.babel.js/webpack/common.js b/modules/web-console/src/main/js/gulpfile.babel.js/webpack/common.js
deleted file mode 100644
index 237f2e7..0000000
--- a/modules/web-console/src/main/js/gulpfile.babel.js/webpack/common.js
+++ /dev/null
@@ -1,192 +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 path from 'path';
-import fs from 'fs';
-import webpack from 'webpack';
-import autoprefixer from 'autoprefixer-core';
-import jade from 'jade';
-import progressPlugin from './plugins/progress';
-import eslintFormatter from 'eslint-friendly-formatter';
-
-import ExtractTextPlugin from 'extract-text-webpack-plugin';
-import HtmlWebpackPlugin from 'html-webpack-plugin';
-
-import {srcDir, destDir, rootDir} from '../paths';
-
-const NODE_ENV = process.env.NODE_ENV || 'production';
-const development = NODE_ENV === 'development';
-const node_modules_path = path.resolve('node_modules');
-const cssLoader = 'css-loader?sourceMap!postcss-loader';
-const stylesLoader = cssLoader + '!sass-loader?outputStyle=expanded&sourceMap=true&sourceMapContents=true';
-
-let favicon;
-
-try {
-    fs.accessSync('build/ignite_modules/favicon.ico', fs.F_OK);
-
-    favicon = 'build/ignite_modules/favicon.ico';
-} catch (ignore) {
-    favicon = 'build/favicon.ico';
-}
-
-export default () => {
-    return {
-        node: {
-            fs: 'empty'
-        },
-
-        // Entry points.
-        entry: {
-            polyfill: 'babel-polyfill',
-            app: path.join(srcDir, 'app.js'),
-            vendor: path.join(srcDir, 'vendor.js')
-        },
-
-        // Output system.
-        output: {
-            path: destDir,
-            publicPath: './',
-            filename: '[name].js'
-        },
-
-        // Resolves modules.
-        resolve: {
-            extensions: [
-                '',
-                '.js'
-            ],
-            root: [rootDir],
-            modulesDirectories: [
-                node_modules_path,
-                './'
-            ]
-        },
-
-        // Modules resolvers.
-        /* global require */
-        module: {
-            noParse: [],
-            preLoaders: [
-                {
-                    test: /\.js$/,
-                    exclude: [node_modules_path],
-                    loader: 'eslint-loader'
-                }
-            ],
-            loaders: [
-                {
-                    test: /\.json$/,
-                    loader: 'json-loader'
-                },
-                {
-                    test: /\.jade$/,
-                    loaders: [
-                        `ngtemplate-loader?relativeTo=${rootDir}`,
-                        'html-loader?attrs[]=img:src&attrs[]=img:data-src',
-                        'jade-html-loader'
-                    ]
-                },
-                {
-                    test: /\.js$/,
-                    exclude: [node_modules_path],
-                    loaders: ['ng-annotate-loader']
-                },
-                {
-                    test: /\.js$/,
-                    exclude: [node_modules_path],
-                    loader: 'babel-loader',
-                    query: {
-                        cacheDirectory: true,
-                        plugins: ['transform-runtime',
-                            'add-module-exports'],
-                        presets: ['angular']
-
-                    }
-                },
-                {
-                    test: /\.css$/,
-                    loader: development ? `style-loader!${cssLoader}` : ExtractTextPlugin.extract('style-loader', cssLoader)
-                },
-                {
-                    test: /\.(scss|sass)$/,
-                    loader: development ? `style-loader!${stylesLoader}` : ExtractTextPlugin.extract('style-loader', stylesLoader)
-                },
-                {
-                    test: /\.(woff2|woff|ttf|eot|svg)?(\?v=[0-9]\.[0-9]\.[0-9])?$/,
-                    loaders: [
-                        'file-loader?name=assets/fonts/[name].[ext]'
-                    ]
-                },
-                {
-                    test: /\.(jpe?g|png|gif)$/i,
-                    loaders: ['file-loader?name=assets/images/[name]_[hash].[ext]']
-                },
-                {
-                    test: require.resolve('jquery'),
-                    loaders: [
-                        'expose-loader?$',
-                        'expose-loader?jQuery'
-                    ]
-                },
-                {
-                    test: require.resolve('nvd3'),
-                    loaders: [
-                        'expose-loader?nv'
-                    ]
-                }
-            ]
-        },
-
-        // Postcss configuration.
-        postcss: [autoprefixer({browsers: ['last 2 versions']})],
-
-        // ESLint loader configuration.
-        eslint: {
-            failOnWarning: false,
-            failOnError: false,
-            formatter: eslintFormatter
-        },
-
-        // Load plugins.
-        plugins: [
-            new webpack.ProvidePlugin({
-                $: 'jquery',
-                jQuery: 'jquery',
-                _: 'lodash',
-                nv: 'nvd3'
-            }),
-            new webpack.DefinePlugin({NODE_ENV: JSON.stringify(NODE_ENV)}),
-            // new webpack.NoErrorsPlugin(),
-            new webpack.optimize.DedupePlugin(),
-            new webpack.optimize.CommonsChunkPlugin({
-                name: 'common',
-                chunks: ['vendor', 'app']
-            }),
-            new webpack.optimize.AggressiveMergingPlugin({moveToParents: true}),
-            new ExtractTextPlugin('assets/css/[name]' + (development ? '' : '.[chunkhash]') + '.css', {allChunks: true}),
-            new HtmlWebpackPlugin({
-                filename: 'index.html',
-                templateContent: () => {
-                    return jade.renderFile(path.join(rootDir, 'views', 'index.jade'));
-                },
-                favicon
-            }),
-            progressPlugin
-        ]
-    };
-};

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/src/main/js/gulpfile.babel.js/webpack/environments/development.js
----------------------------------------------------------------------
diff --git a/modules/web-console/src/main/js/gulpfile.babel.js/webpack/environments/development.js b/modules/web-console/src/main/js/gulpfile.babel.js/webpack/environments/development.js
deleted file mode 100644
index aad4b37..0000000
--- a/modules/web-console/src/main/js/gulpfile.babel.js/webpack/environments/development.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.
- */
-
-import webpack from 'webpack';
-import {destDir, rootDir} from '../../paths';
-
-export default () => {
-    const plugins = [
-        new webpack.HotModuleReplacementPlugin()
-    ];
-
-    return {
-        context: rootDir,
-        debug: true,
-        devtool: 'source-map',
-        watch: true,
-        devServer: {
-            historyApiFallback: true,
-            publicPath: '/',
-            contentBase: destDir,
-            info: true,
-            hot: true,
-            inline: true,
-            proxy: {
-                '/socket.io': {
-                    target: 'http://localhost:3000',
-                    changeOrigin: true,
-                    ws: true
-                },
-                '/api/v1/*': {
-                    target: 'http://localhost:3000',
-                    changeOrigin: true,
-                    rewrite: (req) => {
-                        req.url = req.url.replace(/^\/api\/v1/, '');
-
-                        return req;
-                    }
-                }
-            },
-            watchOptions: {
-                aggregateTimeout: 1000,
-                poll: 1000
-            },
-            stats: {colors: true},
-            port: 9000
-        },
-        stats: {colors: true},
-        plugins
-    };
-};

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/src/main/js/gulpfile.babel.js/webpack/environments/production.js
----------------------------------------------------------------------
diff --git a/modules/web-console/src/main/js/gulpfile.babel.js/webpack/environments/production.js b/modules/web-console/src/main/js/gulpfile.babel.js/webpack/environments/production.js
deleted file mode 100644
index db66720..0000000
--- a/modules/web-console/src/main/js/gulpfile.babel.js/webpack/environments/production.js
+++ /dev/null
@@ -1,45 +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 webpack from 'webpack';
-
-import {destDir, rootDir} from '../../paths';
-
-export default () => {
-    const plugins = [
-        new webpack.optimize.UglifyJsPlugin({
-            path: destDir,
-            minimize: true,
-            warnings: false,
-            sourceMap: false,
-            mangle: true
-        })
-    ];
-
-    return {
-        context: rootDir,
-        bail: true, // Cancel build on error.
-        debug: false,
-        devtool: 'cheap-source-map',
-        output: {
-            publicPath: '/',
-            filename: '[name].[chunkhash].js',
-            path: destDir
-        },
-        plugins
-    };
-};

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/src/main/js/gulpfile.babel.js/webpack/index.js
----------------------------------------------------------------------
diff --git a/modules/web-console/src/main/js/gulpfile.babel.js/webpack/index.js b/modules/web-console/src/main/js/gulpfile.babel.js/webpack/index.js
deleted file mode 100644
index 6682f9c..0000000
--- a/modules/web-console/src/main/js/gulpfile.babel.js/webpack/index.js
+++ /dev/null
@@ -1,32 +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 _ from 'lodash';
-import commonConfig from './common';
-import devConfig from './environments/development';
-import prodConfig from './environments/production';
-
-const env = process.env.NODE_ENV || 'production';
-
-// Config by environments.
-const configs = {
-    production: prodConfig,
-    development: devConfig
-};
-
-// Load config file by environment
-export default _.merge(commonConfig(), configs[env]());

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/src/main/js/gulpfile.babel.js/webpack/plugins/progress.js
----------------------------------------------------------------------
diff --git a/modules/web-console/src/main/js/gulpfile.babel.js/webpack/plugins/progress.js b/modules/web-console/src/main/js/gulpfile.babel.js/webpack/plugins/progress.js
deleted file mode 100644
index 5f753c7..0000000
--- a/modules/web-console/src/main/js/gulpfile.babel.js/webpack/plugins/progress.js
+++ /dev/null
@@ -1,82 +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 ProgressPlugin from 'webpack/lib/ProgressPlugin';
-
-let chars = 0;
-let lastState = 0;
-let lastStateTime = 0;
-
-const outputStream = process.stdout;
-
-const _goToLineStart = (nextMessage) => {
-    let str = '';
-
-    for (; chars > nextMessage.length; chars--)
-        str += '\b \b';
-
-    chars = nextMessage.length;
-
-    for (let i = 0; i < chars; i++)
-        str += '\b';
-
-    if (str)
-        outputStream.write(str);
-};
-
-export default new ProgressPlugin((percentage, msg) => {
-    let state = msg;
-
-    if (percentage < 1) {
-        percentage = Math.floor(percentage * 100);
-
-        msg = percentage + '% ' + msg;
-
-        if (percentage < 100)
-            msg = ' ' + msg;
-
-        if (percentage < 10)
-            msg = ' ' + msg;
-    }
-
-    state = state.replace(/^\d+\/\d+\s+/, '');
-
-    if (percentage === 0) {
-        lastState = null;
-        lastStateTime = (new Date()).getTime();
-    }
-    else if (state !== lastState || percentage === 1) {
-        const now = (new Date()).getTime();
-
-        if (lastState) {
-            const stateMsg = (now - lastStateTime) + 'ms ' + lastState;
-
-            _goToLineStart(stateMsg);
-
-            outputStream.write(stateMsg + '\n');
-
-            chars = 0;
-        }
-
-        lastState = state;
-        lastStateTime = now;
-    }
-
-    _goToLineStart(msg);
-
-    outputStream.write(msg);
-});

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/src/main/js/ignite_modules/README.txt
----------------------------------------------------------------------
diff --git a/modules/web-console/src/main/js/ignite_modules/README.txt b/modules/web-console/src/main/js/ignite_modules/README.txt
deleted file mode 100644
index 365abc7..0000000
--- a/modules/web-console/src/main/js/ignite_modules/README.txt
+++ /dev/null
@@ -1,6 +0,0 @@
-Ignite Web Console Modules
-======================================
-
-If you are are planning to create or use custom modules you need to copy them in this folder before build.
-
-This is default folder for user modules.

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/src/main/js/ignite_modules/index.js
----------------------------------------------------------------------
diff --git a/modules/web-console/src/main/js/ignite_modules/index.js b/modules/web-console/src/main/js/ignite_modules/index.js
deleted file mode 100644
index c38d2d4..0000000
--- a/modules/web-console/src/main/js/ignite_modules/index.js
+++ /dev/null
@@ -1,27 +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 angular from 'angular';
-
-/* ignite:modules */
-/* endignite */
-
-angular
-.module('ignite-console.modules', [
-    /* ignite-console:modules */
-    /* endignite */
-]);

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/src/main/js/package.json
----------------------------------------------------------------------
diff --git a/modules/web-console/src/main/js/package.json b/modules/web-console/src/main/js/package.json
deleted file mode 100644
index b2c648d..0000000
--- a/modules/web-console/src/main/js/package.json
+++ /dev/null
@@ -1,128 +0,0 @@
-{
-  "name": "ignite-web-console",
-  "version": "1.0.0",
-  "description": "Interactive Web console for configuration, executing SQL queries and monitoring of Apache Ignite Cluster",
-  "private": true,
-  "scripts": {
-    "dev": "cross-env NODE_ENV=development gulp watch",
-    "build": "cross-env NODE_ENV=production gulp build",
-    "eslint": "eslint --env node --format node_modules/eslint-friendly-formatter gulpfile.babel.js/ serve/ app/ controllers/ generator/ ignite_modules/ ignite_modules_temp/"
-  },
-  "author": "",
-  "contributors": [
-    {
-      "name": "",
-      "email": ""
-    }
-  ],
-  "license": "Apache-2.0",
-  "keywords": "grid",
-  "homepage": "https://ignite.apache.org/",
-  "engines": {
-    "npm": "^3.x.x",
-    "node": "^4.x.x"
-  },
-  "os": [
-    "darwin",
-    "linux",
-    "win32"
-  ],
-  "dependencies": {
-    "angular": "^1.5.5",
-    "angular-animate": "^1.5.5",
-    "angular-aria": "^1.5.5",
-    "angular-cookies": "^1.5.5",
-    "angular-drag-and-drop-lists": "^1.4.0",
-    "angular-gridster": "^0.13.3",
-    "angular-motion": "^0.4.4",
-    "angular-nvd3": "^1.0.7",
-    "angular-retina": "^0.3.13",
-    "angular-sanitize": "^1.5.5",
-    "angular-smart-table": "^2.1.8",
-    "angular-socket-io": "^0.7.0",
-    "angular-strap": "^2.3.8",
-    "angular-touch": "^1.5.5",
-    "angular-tree-control": "^0.2.26",
-    "angular-ui-grid": "^3.1.1",
-    "angular-ui-router": "^0.3.1",
-    "body-parser": "^1.15.0",
-    "bootstrap-sass": "^3.3.6",
-    "brace": "^0.8.0",
-    "connect-mongo": "^1.1.0",
-    "cookie-parser": "~1.4.0",
-    "es6-promise": "^3.0.2",
-    "express": "^4.14.0",
-    "express-session": "^1.12.0",
-    "file-saver": "^1.3.2",
-    "fire-up": "^1.0.0",
-    "font-awesome": "^4.6.3",
-    "glob": "^7.0.3",
-    "jquery": "^3.0.0",
-    "jszip": "^3.0.0",
-    "lodash": "^4.8.2",
-    "mongoose": "^4.4.11",
-    "mongoose-deep-populate": "^3.0.0",
-    "nconf": "^0.8.2",
-    "nodemailer": "^2.3.0",
-    "nvd3": "^1.8.3",
-    "passport": "^0.3.2",
-    "passport-local": "^1.0.0",
-    "passport-local-mongoose": "^4.0.0",
-    "passport.socketio": "^3.6.1",
-    "query-command-supported": "^1.0.0",
-    "require-dir": "^0.3.0",
-    "socket.io": "^1.4.5",
-    "socket.io-client": "^1.4.6",
-    "ui-router-metatags": "^1.0.3",
-    "ws": "^0.8.0"
-  },
-  "devDependencies": {
-    "assets-webpack-plugin": "^3.2.0",
-    "autoprefixer-core": "^6.0.1",
-    "babel-core": "^6.7.6",
-    "babel-eslint": "^6.0.4",
-    "babel-loader": "^6.2.4",
-    "babel-plugin-add-module-exports": "^0.2.1",
-    "babel-plugin-transform-runtime": "^6.7.5",
-    "babel-polyfill": "^6.7.4",
-    "babel-preset-angular": "^6.0.15",
-    "babel-runtime": "^6.6.1",
-    "bootstrap-loader": "^1.0.10",
-    "cross-env": "^1.0.7",
-    "css-loader": "^0.23.0",
-    "eslint": "^2.9.0",
-    "eslint-friendly-formatter": "^2.0.5",
-    "eslint-loader": "^1.0.0",
-    "expose-loader": "^0.7.1",
-    "extract-text-webpack-plugin": "^1.0.1",
-    "file-loader": "^0.9.0",
-    "gulp": "^3.9.1",
-    "gulp-eslint": "^2.0.0",
-    "gulp-inject": "^4.0.0",
-    "gulp-jade": "^1.1.0",
-    "gulp-rimraf": "^0.2.0",
-    "gulp-sequence": "^0.4.1",
-    "gulp-util": "^3.0.7",
-    "html-loader": "^0.4.3",
-    "html-webpack-plugin": "^2.21.0",
-    "imagemin-pngquant": "^5.0.0",
-    "jade": "^1.11.0",
-    "jade-html-loader": "0.0.3",
-    "json-loader": "^0.5.4",
-    "mocha": "~2.5.3",
-    "morgan": "^1.7.0",
-    "ng-annotate-loader": "0.1.0",
-    "ngtemplate-loader": "^1.3.1",
-    "node-sass": "^3.4.2",
-    "postcss-loader": "^0.9.1",
-    "resolve-url-loader": "^1.4.3",
-    "sass-loader": "^3.1.1",
-    "should": "^9.0.2",
-    "style-loader": "^0.13.1",
-    "supertest": "^1.1.0",
-    "url": "^0.11.0",
-    "url-loader": "^0.5.6",
-    "webpack": "^1.13.1",
-    "webpack-dev-server": "^1.14.1"
-  }
-}

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/src/main/js/public/favicon.ico
----------------------------------------------------------------------
diff --git a/modules/web-console/src/main/js/public/favicon.ico b/modules/web-console/src/main/js/public/favicon.ico
deleted file mode 100644
index b36f8d7..0000000
Binary files a/modules/web-console/src/main/js/public/favicon.ico and /dev/null differ

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/src/main/js/public/images/cache.png
----------------------------------------------------------------------
diff --git a/modules/web-console/src/main/js/public/images/cache.png b/modules/web-console/src/main/js/public/images/cache.png
deleted file mode 100644
index 83fd987..0000000
Binary files a/modules/web-console/src/main/js/public/images/cache.png and /dev/null differ

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/src/main/js/public/images/cluster.png
----------------------------------------------------------------------
diff --git a/modules/web-console/src/main/js/public/images/cluster.png b/modules/web-console/src/main/js/public/images/cluster.png
deleted file mode 100644
index 2d8b860..0000000
Binary files a/modules/web-console/src/main/js/public/images/cluster.png and /dev/null differ

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/src/main/js/public/images/docker.png
----------------------------------------------------------------------
diff --git a/modules/web-console/src/main/js/public/images/docker.png b/modules/web-console/src/main/js/public/images/docker.png
deleted file mode 100644
index afc5df4..0000000
Binary files a/modules/web-console/src/main/js/public/images/docker.png and /dev/null differ

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/src/main/js/public/images/domains.png
----------------------------------------------------------------------
diff --git a/modules/web-console/src/main/js/public/images/domains.png b/modules/web-console/src/main/js/public/images/domains.png
deleted file mode 100644
index 39abfcb..0000000
Binary files a/modules/web-console/src/main/js/public/images/domains.png and /dev/null differ

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/src/main/js/public/images/igfs.png
----------------------------------------------------------------------
diff --git a/modules/web-console/src/main/js/public/images/igfs.png b/modules/web-console/src/main/js/public/images/igfs.png
deleted file mode 100644
index 47c659e..0000000
Binary files a/modules/web-console/src/main/js/public/images/igfs.png and /dev/null differ

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/src/main/js/public/images/ignite-logo.png
----------------------------------------------------------------------
diff --git a/modules/web-console/src/main/js/public/images/ignite-logo.png b/modules/web-console/src/main/js/public/images/ignite-logo.png
deleted file mode 100644
index ea08d1b..0000000
Binary files a/modules/web-console/src/main/js/public/images/ignite-logo.png and /dev/null differ

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/src/main/js/public/images/ignite-logo@2x.png
----------------------------------------------------------------------
diff --git a/modules/web-console/src/main/js/public/images/ignite-logo@2x.png b/modules/web-console/src/main/js/public/images/ignite-logo@2x.png
deleted file mode 100644
index 10005db..0000000
Binary files a/modules/web-console/src/main/js/public/images/ignite-logo@2x.png and /dev/null differ

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/src/main/js/public/images/ignite-puzzle.png
----------------------------------------------------------------------
diff --git a/modules/web-console/src/main/js/public/images/ignite-puzzle.png b/modules/web-console/src/main/js/public/images/ignite-puzzle.png
deleted file mode 100644
index 0989d29..0000000
Binary files a/modules/web-console/src/main/js/public/images/ignite-puzzle.png and /dev/null differ

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/src/main/js/public/images/java.png
----------------------------------------------------------------------
diff --git a/modules/web-console/src/main/js/public/images/java.png b/modules/web-console/src/main/js/public/images/java.png
deleted file mode 100644
index ddb3b8e..0000000
Binary files a/modules/web-console/src/main/js/public/images/java.png and /dev/null differ

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/src/main/js/public/images/pb-ignite.png
----------------------------------------------------------------------
diff --git a/modules/web-console/src/main/js/public/images/pb-ignite.png b/modules/web-console/src/main/js/public/images/pb-ignite.png
deleted file mode 100644
index 55f6746..0000000
Binary files a/modules/web-console/src/main/js/public/images/pb-ignite.png and /dev/null differ

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/src/main/js/public/images/pb-ignite@2x.png
----------------------------------------------------------------------
diff --git a/modules/web-console/src/main/js/public/images/pb-ignite@2x.png b/modules/web-console/src/main/js/public/images/pb-ignite@2x.png
deleted file mode 100644
index ffcff38..0000000
Binary files a/modules/web-console/src/main/js/public/images/pb-ignite@2x.png and /dev/null differ

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/src/main/js/public/images/query-chart.png
----------------------------------------------------------------------
diff --git a/modules/web-console/src/main/js/public/images/query-chart.png b/modules/web-console/src/main/js/public/images/query-chart.png
deleted file mode 100644
index c6e4cce..0000000
Binary files a/modules/web-console/src/main/js/public/images/query-chart.png and /dev/null differ

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/src/main/js/public/images/query-metadata.png
----------------------------------------------------------------------
diff --git a/modules/web-console/src/main/js/public/images/query-metadata.png b/modules/web-console/src/main/js/public/images/query-metadata.png
deleted file mode 100644
index 698cd6e..0000000
Binary files a/modules/web-console/src/main/js/public/images/query-metadata.png and /dev/null differ

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/src/main/js/public/images/query-table.png
----------------------------------------------------------------------
diff --git a/modules/web-console/src/main/js/public/images/query-table.png b/modules/web-console/src/main/js/public/images/query-table.png
deleted file mode 100644
index 53becda..0000000
Binary files a/modules/web-console/src/main/js/public/images/query-table.png and /dev/null differ

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/src/main/js/public/images/summary.png
----------------------------------------------------------------------
diff --git a/modules/web-console/src/main/js/public/images/summary.png b/modules/web-console/src/main/js/public/images/summary.png
deleted file mode 100644
index ff88438..0000000
Binary files a/modules/web-console/src/main/js/public/images/summary.png and /dev/null differ

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/src/main/js/public/images/xml.png
----------------------------------------------------------------------
diff --git a/modules/web-console/src/main/js/public/images/xml.png b/modules/web-console/src/main/js/public/images/xml.png
deleted file mode 100644
index 029065e..0000000
Binary files a/modules/web-console/src/main/js/public/images/xml.png and /dev/null differ

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/src/main/js/public/stylesheets/_bootstrap-custom.scss
----------------------------------------------------------------------
diff --git a/modules/web-console/src/main/js/public/stylesheets/_bootstrap-custom.scss b/modules/web-console/src/main/js/public/stylesheets/_bootstrap-custom.scss
deleted file mode 100644
index 3b52821..0000000
--- a/modules/web-console/src/main/js/public/stylesheets/_bootstrap-custom.scss
+++ /dev/null
@@ -1,65 +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.
- */
-
-// Core variables and mixins
-@import "bootstrap-variables";
-@import "../../node_modules/bootstrap-sass/assets/stylesheets/bootstrap/mixins";
-
-// Reset and dependencies
-@import "../../node_modules/bootstrap-sass/assets/stylesheets/bootstrap/normalize";
-@import "../../node_modules/bootstrap-sass/assets/stylesheets/bootstrap/print";
-
-// Core CSS
-@import "../../node_modules/bootstrap-sass/assets/stylesheets/bootstrap/scaffolding";
-@import "../../node_modules/bootstrap-sass/assets/stylesheets/bootstrap/type";
-@import "../../node_modules/bootstrap-sass/assets/stylesheets/bootstrap/code";
-@import "../../node_modules/bootstrap-sass/assets/stylesheets/bootstrap/grid";
-@import "../../node_modules/bootstrap-sass/assets/stylesheets/bootstrap/tables";
-@import "../../node_modules/bootstrap-sass/assets/stylesheets/bootstrap/forms";
-@import "../../node_modules/bootstrap-sass/assets/stylesheets/bootstrap/buttons";
-
-// Components
-@import "../../node_modules/bootstrap-sass/assets/stylesheets/bootstrap/component-animations";
-@import "../../node_modules/bootstrap-sass/assets/stylesheets/bootstrap/dropdowns";
-@import "../../node_modules/bootstrap-sass/assets/stylesheets/bootstrap/button-groups";
-@import "../../node_modules/bootstrap-sass/assets/stylesheets/bootstrap/input-groups";
-@import "../../node_modules/bootstrap-sass/assets/stylesheets/bootstrap/navs";
-@import "../../node_modules/bootstrap-sass/assets/stylesheets/bootstrap/navbar";
-@import "../../node_modules/bootstrap-sass/assets/stylesheets/bootstrap/pagination";
-@import "../../node_modules/bootstrap-sass/assets/stylesheets/bootstrap/pager";
-@import "../../node_modules/bootstrap-sass/assets/stylesheets/bootstrap/labels";
-@import "../../node_modules/bootstrap-sass/assets/stylesheets/bootstrap/badges";
-@import "../../node_modules/bootstrap-sass/assets/stylesheets/bootstrap/jumbotron";
-@import "../../node_modules/bootstrap-sass/assets/stylesheets/bootstrap/thumbnails";
-@import "../../node_modules/bootstrap-sass/assets/stylesheets/bootstrap/alerts";
-@import "../../node_modules/bootstrap-sass/assets/stylesheets/bootstrap/progress-bars";
-@import "../../node_modules/bootstrap-sass/assets/stylesheets/bootstrap/media";
-@import "../../node_modules/bootstrap-sass/assets/stylesheets/bootstrap/list-group";
-@import "../../node_modules/bootstrap-sass/assets/stylesheets/bootstrap/panels";
-@import "../../node_modules/bootstrap-sass/assets/stylesheets/bootstrap/responsive-embed";
-@import "../../node_modules/bootstrap-sass/assets/stylesheets/bootstrap/wells";
-@import "../../node_modules/bootstrap-sass/assets/stylesheets/bootstrap/close";
-
-// Components w/ JavaScript
-@import "../../node_modules/bootstrap-sass/assets/stylesheets/bootstrap/modals";
-@import "../../node_modules/bootstrap-sass/assets/stylesheets/bootstrap/tooltip";
-@import "../../node_modules/bootstrap-sass/assets/stylesheets/bootstrap/popovers";
-@import "../../node_modules/bootstrap-sass/assets/stylesheets/bootstrap/carousel";
-
-// Utility classes
-@import "../../node_modules/bootstrap-sass/assets/stylesheets/bootstrap/utilities";
-@import "../../node_modules/bootstrap-sass/assets/stylesheets/bootstrap/responsive-utilities";

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/src/main/js/public/stylesheets/_bootstrap-variables.scss
----------------------------------------------------------------------
diff --git a/modules/web-console/src/main/js/public/stylesheets/_bootstrap-variables.scss b/modules/web-console/src/main/js/public/stylesheets/_bootstrap-variables.scss
deleted file mode 100644
index fe0ac18..0000000
--- a/modules/web-console/src/main/js/public/stylesheets/_bootstrap-variables.scss
+++ /dev/null
@@ -1,891 +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.
- */
-
-$bootstrap-sass-asset-helper: false !default;
-//
-// Variables
-// --------------------------------------------------
-
-
-//== Colors
-//
-//## Gray and brand colors for use across Bootstrap.
-
-$gray-base:              #000 !default;
-$gray-darker:            lighten($gray-base, 13.5%) !default; // #222
-$gray-dark:              lighten($gray-base, 20%) !default;   // #333
-$gray:                   lighten($gray-base, 33.5%) !default; // #555
-$gray-light:             lighten($gray-base, 46.7%) !default; // #777
-$gray-lighter:           lighten($gray-base, 93.5%) !default; // #eee
-
-$brand-primary:         #ec1c24 !default;
-$brand-success:         #50af51 !default;
-$brand-info:            #248fb2 !default;
-$brand-warning:         #f0ad4e !default;
-$brand-danger:          #d9534f !default;
-
-
-//== Scaffolding
-//
-//## Settings for some of the most global styles.
-
-//** Background color for `<body>`.
-$body-bg:               #f9f9f9 !default;
-//** Global text color on `<body>`.
-$text-color:            $gray-dark !default;
-
-//** Global textual link color.
-$link-color:            $brand-primary !default;
-//** Link hover color set via `darken()` function.
-$link-hover-color:      darken($link-color, 15%) !default;
-//** Link hover decoration.
-$link-hover-decoration: underline !default;
-
-
-//== Typography
-//
-//## Font, line-height, and color for body text, headings, and more.
-
-$font-family-sans-serif:  Roboto Slab, sans-serif !default;
-$font-family-serif:       Roboto Slab, serif !default;
-//** Default monospace fonts for `<code>`, `<kbd>`, and `<pre>`.
-$font-family-monospace:   Menlo, Monaco, Consolas, "Courier New", monospace !default;
-$font-family-base:        $font-family-sans-serif !default;
-
-$font-size-base:          14px !default;
-$font-size-large:         ceil(($font-size-base * 1.25)) !default; // ~18px
-$font-size-small:         ceil(($font-size-base * 0.85)) !default; // ~12px
-
-$font-size-h1:            floor(($font-size-base * 2.6)) !default; // ~36px
-$font-size-h2:            floor(($font-size-base * 2.15)) !default; // ~30px
-$font-size-h3:            ceil(($font-size-base * 1.7)) !default; // ~24px
-$font-size-h4:            ceil(($font-size-base * 1.25)) !default; // ~18px
-$font-size-h5:            $font-size-base !default;
-$font-size-h6:            ceil(($font-size-base * 0.85)) !default; // ~12px
-
-//** Unit-less `line-height` for use in components like buttons.
-$line-height-base:        1.428571429 !default; // 20/14
-//** Computed "line-height" (`font-size` * `line-height`) for use with `margin`, `padding`, etc.
-$line-height-computed:    floor(($font-size-base * $line-height-base)) !default; // ~20px
-
-//** By default, this inherits from the `<body>`.
-$headings-font-family:    inherit !default;
-$headings-font-weight:    500 !default;
-$headings-line-height:    1.1 !default;
-$headings-color:          inherit !default;
-
-
-//== Iconography
-//
-//## Specify custom location and filename of the included Glyphicons icon font. Useful for those including Bootstrap via Bower.
-
-//** Load fonts from this directory.
-
-// [converter] If $bootstrap-sass-asset-helper if used, provide path relative to the assets load path.
-// [converter] This is because some asset helpers, such as Sprockets, do not work with file-relative paths.
-$icon-font-path: if($bootstrap-sass-asset-helper, "bootstrap/", "../fonts/bootstrap/") !default;
-
-//** File name for all font files.
-$icon-font-name:          "glyphicons-halflings-regular" !default;
-//** Element ID within SVG icon file.
-$icon-font-svg-id:        "glyphicons_halflingsregular" !default;
-
-
-//== Components
-//
-//## Define common padding and border radius sizes and more. Values based on 14px text and 1.428 line-height (~20px to start).
-
-$padding-base-vertical:     6px !default;
-$padding-base-horizontal:   12px !default;
-
-$padding-large-vertical:    10px !default;
-$padding-large-horizontal:  16px !default;
-
-$padding-small-vertical:    5px !default;
-$padding-small-horizontal:  10px !default;
-
-$padding-xs-vertical:       1px !default;
-$padding-xs-horizontal:     5px !default;
-
-$line-height-large:         1.3333333 !default; // extra decimals for Win 8.1 Chrome
-$line-height-small:         1.5 !default;
-
-$border-radius-base:        4px !default;
-$border-radius-large:       6px !default;
-$border-radius-small:       3px !default;
-
-//** Global color for active items (e.g., navs or dropdowns).
-$component-active-color:    $link-color !default;
-//** Global background color for active items (e.g., navs or dropdowns).
-$component-active-bg:       $brand-primary !default;
-
-//** Width of the `border` for generating carets that indicator dropdowns.
-$caret-width-base:          4px !default;
-//** Carets increase slightly in size for larger components.
-$caret-width-large:         5px !default;
-
-
-//== Tables
-//
-//## Customizes the `.table` component with basic values, each used across all table variations.
-
-//** Padding for `<th>`s and `<td>`s.
-$table-cell-padding:            8px !default;
-//** Padding for cells in `.table-condensed`.
-$table-condensed-cell-padding:  5px !default;
-
-//** Default background color used for all tables.
-$table-bg:                      transparent !default;
-//** Background color used for `.table-striped`.
-$table-bg-accent:               #f9f9f9 !default;
-//** Background color used for `.table-hover`.
-$table-bg-hover:                #f5f5f5 !default;
-$table-bg-active:               $table-bg-hover !default;
-
-//** Border color for table and cell borders.
-$table-border-color:            #ddd !default;
-
-
-//== Buttons
-//
-//## For each of Bootstrap's buttons, define text, background and border color.
-
-$btn-font-weight:                normal !default;
-
-$btn-default-color:              #333 !default;
-$btn-default-bg:                 #fff !default;
-$btn-default-border:             #ccc !default;
-
-$btn-primary-color:              #fff !default;
-$btn-primary-bg:                 $brand-primary !default;
-$btn-primary-border:             darken($btn-primary-bg, 15%) !default;
-
-$btn-success-color:              #fff !default;
-$btn-success-bg:                 $brand-success !default;
-$btn-success-border:             darken($btn-success-bg, 5%) !default;
-
-$btn-info-color:                 #fff !default;
-$btn-info-bg:                    $brand-info !default;
-$btn-info-border:                darken($btn-info-bg, 5%) !default;
-
-$btn-warning-color:              #fff !default;
-$btn-warning-bg:                 $brand-warning !default;
-$btn-warning-border:             darken($btn-warning-bg, 5%) !default;
-
-$btn-danger-color:               #fff !default;
-$btn-danger-bg:                  $brand-danger !default;
-$btn-danger-border:              darken($btn-danger-bg, 5%) !default;
-
-$btn-link-disabled-color:        $gray-light !default;
-
-// Allows for customizing button radius independently from global border radius
-$btn-border-radius-base:         $border-radius-base !default;
-$btn-border-radius-large:        $border-radius-large !default;
-$btn-border-radius-small:        $border-radius-small !default;
-
-
-//== Forms
-//
-//##
-
-//** `<input>` background color
-$input-bg:                       #fff !default;
-//** `<input disabled>` background color
-$input-bg-disabled:              $gray-lighter !default;
-
-//** Text color for `<input>`s
-$input-color:                    $gray !default;
-//** `<input>` border color
-$input-border:                   #ccc !default;
-
-// TODO: Rename `$input-border-radius` to `$input-border-radius-base` in v4
-//** Default `.form-control` border radius
-// This has no effect on `<select>`s in some browsers, due to the limited stylability of `<select>`s in CSS.
-$input-border-radius:            $border-radius-base !default;
-//** Large `.form-control` border radius
-$input-border-radius-large:      $border-radius-large !default;
-//** Small `.form-control` border radius
-$input-border-radius-small:      $border-radius-small !default;
-
-//** Border color for inputs on focus
-$input-border-focus:             #66afe9 !default;
-
-//** Placeholder text color
-$input-color-placeholder:        #999 !default;
-
-//** Default `.form-control` height
-$input-height-base:              ($line-height-computed + ($padding-base-vertical * 2) + 2) !default;
-//** Large `.form-control` height
-$input-height-large:             (ceil($font-size-large * $line-height-large) + ($padding-large-vertical * 2) + 2) !default;
-//** Small `.form-control` height
-$input-height-small:             (floor($font-size-small * $line-height-small) + ($padding-small-vertical * 2) + 2) !default;
-
-//** `.form-group` margin
-$form-group-margin-bottom:       15px !default;
-
-$legend-color:                   $gray-dark !default;
-$legend-border-color:            #e5e5e5 !default;
-
-//** Background color for textual input addons
-$input-group-addon-bg:           $gray-lighter !default;
-//** Border color for textual input addons
-$input-group-addon-border-color: $input-border !default;
-
-//** Disabled cursor for form controls and buttons.
-$cursor-disabled:                not-allowed !default;
-
-
-//== Dropdowns
-//
-//## Dropdown menu container and contents.
-
-//** Background for the dropdown menu.
-$dropdown-bg:                    #fff !default;
-//** Dropdown menu `border-color`.
-$dropdown-border:                rgba(0,0,0,.15) !default;
-//** Dropdown menu `border-color` **for IE8**.
-$dropdown-fallback-border:       #ccc !default;
-//** Divider color for between dropdown items.
-$dropdown-divider-bg:            #e5e5e5 !default;
-
-//** Dropdown link text color.
-$dropdown-link-color:            #555 !default;
-//** Hover color for dropdown links.
-$dropdown-link-hover-color:      $link-hover-color !default;
-//** Hover background for dropdown links.
-$dropdown-link-hover-bg:         transparent !default;
-
-//** Active dropdown menu item text color.
-$dropdown-link-active-color:     $component-active-color !default;
-//** Active dropdown menu item background color.
-$dropdown-link-active-bg:        transparent !default;
-
-//** Disabled dropdown menu item background color.
-$dropdown-link-disabled-color:   $gray-light !default;
-
-//** Text color for headers within dropdown menus.
-$dropdown-header-color:          $gray-light !default;
-
-//** Deprecated `$dropdown-caret-color` as of v3.1.0
-$dropdown-caret-color:           #000 !default;
-
-
-//-- Z-index master list
-//
-// Warning: Avoid customizing these values. They're used for a bird's eye view
-// of components dependent on the z-axis and are designed to all work together.
-//
-// Note: These variables are not generated into the Customizer.
-
-$zindex-navbar:            1000 !default;
-$zindex-dropdown:          1002 !default;
-$zindex-popover:           1060 !default;
-$zindex-tooltip:           1070 !default;
-$zindex-navbar-fixed:      1030 !default;
-$zindex-modal-background:  1040 !default;
-$zindex-modal:             1050 !default;
-
-
-//== Media queries breakpoints
-//
-//## Define the breakpoints at which your layout will change, adapting to different screen sizes.
-
-// Extra small screen / phone
-//** Deprecated `$screen-xs` as of v3.0.1
-$screen-xs:                  480px !default;
-//** Deprecated `$screen-xs-min` as of v3.2.0
-$screen-xs-min:              $screen-xs !default;
-//** Deprecated `$screen-phone` as of v3.0.1
-$screen-phone:               $screen-xs-min !default;
-
-// Small screen / tablet
-//** Deprecated `$screen-sm` as of v3.0.1
-$screen-sm:                  768px !default;
-$screen-sm-min:              $screen-sm !default;
-//** Deprecated `$screen-tablet` as of v3.0.1
-$screen-tablet:              $screen-sm-min !default;
-
-// Medium screen / desktop
-//** Deprecated `$screen-md` as of v3.0.1
-$screen-md:                  992px !default;
-$screen-md-min:              $screen-md !default;
-//** Deprecated `$screen-desktop` as of v3.0.1
-$screen-desktop:             $screen-md-min !default;
-
-// Large screen / wide desktop
-//** Deprecated `$screen-lg` as of v3.0.1
-$screen-lg:                  1200px !default;
-$screen-lg-min:              $screen-lg !default;
-//** Deprecated `$screen-lg-desktop` as of v3.0.1
-$screen-lg-desktop:          $screen-lg-min !default;
-
-// So media queries don't overlap when required, provide a maximum
-$screen-xs-max:              ($screen-sm-min - 1) !default;
-$screen-sm-max:              ($screen-md-min - 1) !default;
-$screen-md-max:              ($screen-lg-min - 1) !default;
-
-
-//== Grid system
-//
-//## Define your custom responsive grid.
-
-//** Number of columns in the grid.
-$grid-columns:              12 !default;
-//** Padding between columns. Gets divided in half for the left and right.
-$grid-gutter-width:         0 !default;
-// Navbar collapse
-//** Point at which the navbar becomes uncollapsed.
-$grid-float-breakpoint:     $screen-sm-min !default;
-//** Point at which the navbar begins collapsing.
-$grid-float-breakpoint-max: ($grid-float-breakpoint - 1) !default;
-
-
-//== Container sizes
-//
-//## Define the maximum width of `.container` for different screen sizes.
-
-// Small screen / tablet
-$container-tablet:             (720px + $grid-gutter-width) !default;
-//** For `$screen-sm-min` and up.
-$container-sm:                 $container-tablet !default;
-
-// Medium screen / desktop
-$container-desktop:            (940px + $grid-gutter-width) !default;
-//** For `$screen-md-min` and up.
-$container-md:                 $container-desktop !default;
-
-// Large screen / wide desktop
-$container-large-desktop:      (1140px + $grid-gutter-width) !default;
-//** For `$screen-lg-min` and up.
-$container-lg:                 $container-large-desktop !default;
-
-
-//== Navbar
-//
-//##
-
-// Basics of a navbar
-$navbar-height:                    50px !default;
-$navbar-margin-bottom:             $line-height-computed !default;
-$navbar-border-radius:             $border-radius-base !default;
-$navbar-padding-horizontal:        floor(($grid-gutter-width / 2)) !default;
-$navbar-padding-vertical:          (($navbar-height - $line-height-computed) / 2) !default;
-$navbar-collapse-max-height:       340px !default;
-
-$navbar-default-color:             #bbb !default;
-$navbar-default-bg:                #f8f8f8 !default;
-$navbar-default-border:            darken($navbar-default-bg, 6.5%) !default;
-
-// Navbar links
-$navbar-default-link-color:                #bbb !default;
-$navbar-default-link-hover-color:          $link-hover-color !default;
-$navbar-default-link-hover-bg:             transparent !default;
-$navbar-default-link-active-color:         $component-active-color !default;
-$navbar-default-link-active-bg:            darken($navbar-default-bg, 6.5%) !default;
-$navbar-default-link-disabled-color:       #ccc !default;
-$navbar-default-link-disabled-bg:          transparent !default;
-
-// Navbar brand label
-$navbar-default-brand-color:               $navbar-default-link-color !default;
-$navbar-default-brand-hover-color:         darken($link-color, 15%) !default;
-$navbar-default-brand-hover-bg:            transparent !default;
-
-// Navbar toggle
-$navbar-default-toggle-hover-bg:           #ddd !default;
-$navbar-default-toggle-icon-bar-bg:        #888 !default;
-$navbar-default-toggle-border-color:       #ddd !default;
-
-
-//=== Inverted navbar
-// Reset inverted navbar basics
-$navbar-inverse-color:                      lighten($gray-light, 15%) !default;
-$navbar-inverse-bg:                         #222 !default;
-$navbar-inverse-border:                     darken($navbar-inverse-bg, 10%) !default;
-
-// Inverted navbar links
-$navbar-inverse-link-color:                 lighten($gray-light, 15%) !default;
-$navbar-inverse-link-hover-color:           #fff !default;
-$navbar-inverse-link-hover-bg:              transparent !default;
-$navbar-inverse-link-active-color:          $navbar-inverse-link-hover-color !default;
-$navbar-inverse-link-active-bg:             darken($navbar-inverse-bg, 10%) !default;
-$navbar-inverse-link-disabled-color:        #444 !default;
-$navbar-inverse-link-disabled-bg:           transparent !default;
-
-// Inverted navbar brand label
-$navbar-inverse-brand-color:                $navbar-inverse-link-color !default;
-$navbar-inverse-brand-hover-color:          #fff !default;
-$navbar-inverse-brand-hover-bg:             transparent !default;
-
-// Inverted navbar toggle
-$navbar-inverse-toggle-hover-bg:            #333 !default;
-$navbar-inverse-toggle-icon-bar-bg:         #fff !default;
-$navbar-inverse-toggle-border-color:        #333 !default;
-
-
-//== Navs
-//
-//##
-
-//=== Shared nav styles
-$nav-link-padding:                          10px 15px !default;
-$nav-link-hover-bg:                         transparent !default;
-
-$nav-disabled-link-color:                   $gray-light !default;
-$nav-disabled-link-hover-color:             $gray-light !default;
-
-//== Tabs
-$nav-tabs-border-color:                     #ddd !default;
-
-$nav-tabs-link-hover-border-color:          $gray-lighter !default;
-
-$nav-tabs-active-link-hover-bg:             $body-bg !default;
-$nav-tabs-active-link-hover-color:          $gray !default;
-$nav-tabs-active-link-hover-border-color:   #ddd !default;
-
-$nav-tabs-justified-link-border-color:            #ddd !default;
-$nav-tabs-justified-active-link-border-color:     $body-bg !default;
-
-//== Pills
-$nav-pills-border-radius:                   $border-radius-base !default;
-$nav-pills-active-link-hover-bg:            $component-active-bg !default;
-$nav-pills-active-link-hover-color:         $component-active-color !default;
-
-
-//== Pagination
-//
-//##
-
-$pagination-color:                     $link-color !default;
-$pagination-bg:                        #fff !default;
-$pagination-border:                    #ddd !default;
-
-$pagination-hover-color:               $link-hover-color !default;
-$pagination-hover-bg:                  $gray-lighter !default;
-$pagination-hover-border:              #ddd !default;
-
-$pagination-active-color:              #fff !default;
-$pagination-active-bg:                 $brand-primary !default;
-$pagination-active-border:             $brand-primary !default;
-
-$pagination-disabled-color:            $gray-light !default;
-$pagination-disabled-bg:               #fff !default;
-$pagination-disabled-border:           #ddd !default;
-
-
-//== Pager
-//
-//##
-
-$pager-bg:                             $pagination-bg !default;
-$pager-border:                         $pagination-border !default;
-$pager-border-radius:                  15px !default;
-
-$pager-hover-bg:                       $pagination-hover-bg !default;
-
-$pager-active-bg:                      $pagination-active-bg !default;
-$pager-active-color:                   $pagination-active-color !default;
-
-$pager-disabled-color:                 $pagination-disabled-color !default;
-
-
-//== Jumbotron
-//
-//##
-
-$jumbotron-padding:              30px !default;
-$jumbotron-color:                inherit !default;
-$jumbotron-bg:                   $gray-lighter !default;
-$jumbotron-heading-color:        inherit !default;
-$jumbotron-font-size:            ceil(($font-size-base * 1.5)) !default;
-$jumbotron-heading-font-size:    ceil(($font-size-base * 4.5)) !default;
-
-
-//== Form states and alerts
-//
-//## Define colors for form feedback states and, by default, alerts.
-
-$state-success-text:             #3c763d !default;
-$state-success-bg:               #dff0d8 !default;
-$state-success-border:           darken(adjust-hue($state-success-bg, -10), 25%) !default;
-
-$state-info-text:                #31708f !default;
-$state-info-bg:                  #d9edf7 !default;
-$state-info-border:              darken(adjust-hue($state-info-bg, -10), 25%) !default;
-
-$state-warning-text:             #8a6d3b !default;
-$state-warning-bg:               #fcf8e3 !default;
-$state-warning-border:           darken(adjust-hue($state-warning-bg, -10), 25%) !default;
-
-$state-danger-text:              #a94442 !default;
-$state-danger-bg:                #f2dede !default;
-$state-danger-border:            darken(adjust-hue($state-danger-bg, -10), 25%) !default;
-
-
-//== Tooltips
-//
-//##
-
-//** Tooltip max width
-$tooltip-max-width:           400px !default;
-//** Tooltip text color
-$tooltip-color:               #000 !default;
-//** Tooltip background color
-$tooltip-bg:                  #f5f5f5 !default;
-$tooltip-opacity:             1 !default;
-
-//** Tooltip arrow width
-$tooltip-arrow-width:         5px !default;
-//** Tooltip arrow color
-$tooltip-arrow-color:         #ccc !default;
-
-
-//== Popovers
-//
-//##
-
-//** Popover body background color
-$popover-bg:                          #fff !default;
-//** Popover maximum width
-$popover-max-width:                   auto !default;
-//** Popover border color
-$popover-border-color:                rgba(0,0,0,.2) !default;
-//** Popover fallback border color
-$popover-fallback-border-color:       #ccc !default;
-
-//** Popover title background color
-$popover-title-bg:                    darken($popover-bg, 3%) !default;
-
-//** Popover arrow width
-$popover-arrow-width:                 10px !default;
-//** Popover arrow color
-$popover-arrow-color:                 $popover-bg !default;
-
-//** Popover outer arrow width
-$popover-arrow-outer-width:           ($popover-arrow-width + 1) !default;
-//** Popover outer arrow color
-$popover-arrow-outer-color:           fade_in($popover-border-color, 0.05) !default;
-//** Popover outer arrow fallback color
-$popover-arrow-outer-fallback-color:  darken($popover-fallback-border-color, 20%) !default;
-
-
-//== Labels
-//
-//##
-
-//** Default label background color
-$label-default-bg:            $gray-light !default;
-//** Primary label background color
-$label-primary-bg:            $brand-primary !default;
-//** Success label background color
-$label-success-bg:            $brand-success !default;
-//** Info label background color
-$label-info-bg:               $brand-info !default;
-//** Warning label background color
-$label-warning-bg:            $brand-warning !default;
-//** Danger label background color
-$label-danger-bg:             $brand-danger !default;
-
-//** Default label text color
-$label-color:                 #fff !default;
-//** Default text color of a linked label
-$label-link-hover-color:      #fff !default;
-
-
-//== Modals
-//
-//##
-
-//** Padding applied to the modal body
-$modal-inner-padding:         15px !default;
-
-//** Padding applied to the modal title
-$modal-title-padding:         15px !default;
-//** Modal title line-height
-$modal-title-line-height:     $line-height-base !default;
-
-//** Background color of modal content area
-$modal-content-bg:                             #fff !default;
-//** Modal content border color
-$modal-content-border-color:                   rgba(0,0,0,.2) !default;
-//** Modal content border color **for IE8**
-$modal-content-fallback-border-color:          #999 !default;
-
-//** Modal backdrop background color
-$modal-backdrop-bg:           #000 !default;
-//** Modal backdrop opacity
-$modal-backdrop-opacity:      .5 !default;
-//** Modal header border color
-$modal-header-border-color:   #e5e5e5 !default;
-//** Modal footer border color
-$modal-footer-border-color:   $modal-header-border-color !default;
-
-$modal-lg:                    900px !default;
-$modal-md:                    600px !default;
-$modal-sm:                    300px !default;
-
-
-//== Alerts
-//
-//## Define alert colors, border radius, and padding.
-
-$alert-padding:               15px !default;
-$alert-border-radius:         $border-radius-base !default;
-$alert-link-font-weight:      bold !default;
-
-$alert-success-bg:            $state-success-bg !default;
-$alert-success-text:          $state-success-text !default;
-$alert-success-border:        $state-success-border !default;
-
-$alert-info-bg:               $state-info-bg !default;
-$alert-info-text:             $state-info-text !default;
-$alert-info-border:           $state-info-border !default;
-
-$alert-warning-bg:            $state-warning-bg !default;
-$alert-warning-text:          $state-warning-text !default;
-$alert-warning-border:        $state-warning-border !default;
-
-$alert-danger-bg:             $state-danger-bg !default;
-$alert-danger-text:           $state-danger-text !default;
-$alert-danger-border:         $state-danger-border !default;
-
-
-//== Progress bars
-//
-//##
-
-//** Background color of the whole progress component
-$progress-bg:                 #f5f5f5 !default;
-//** Progress bar text color
-$progress-bar-color:          #fff !default;
-//** Variable for setting rounded corners on progress bar.
-$progress-border-radius:      $border-radius-base !default;
-
-//** Default progress bar color
-$progress-bar-bg:             $brand-primary !default;
-//** Success progress bar color
-$progress-bar-success-bg:     $brand-success !default;
-//** Warning progress bar color
-$progress-bar-warning-bg:     $brand-warning !default;
-//** Danger progress bar color
-$progress-bar-danger-bg:      $brand-danger !default;
-//** Info progress bar color
-$progress-bar-info-bg:        $brand-info !default;
-
-
-//== List group
-//
-//##
-
-//** Background color on `.list-group-item`
-$list-group-bg:                 #fff !default;
-//** `.list-group-item` border color
-$list-group-border:             #ddd !default;
-//** List group border radius
-$list-group-border-radius:      $border-radius-base !default;
-
-//** Background color of single list items on hover
-$list-group-hover-bg:           #f5f5f5 !default;
-//** Text color of active list items
-$list-group-active-color:       $component-active-color !default;
-//** Background color of active list items
-$list-group-active-bg:          $component-active-bg !default;
-//** Border color of active list elements
-$list-group-active-border:      $list-group-active-bg !default;
-//** Text color for content within active list items
-$list-group-active-text-color:  lighten($list-group-active-bg, 40%) !default;
-
-//** Text color of disabled list items
-$list-group-disabled-color:      $gray-light !default;
-//** Background color of disabled list items
-$list-group-disabled-bg:         $gray-lighter !default;
-//** Text color for content within disabled list items
-$list-group-disabled-text-color: $list-group-disabled-color !default;
-
-$list-group-link-color:         #555 !default;
-$list-group-link-hover-color:   $list-group-link-color !default;
-$list-group-link-heading-color: #333 !default;
-
-
-//== Panels
-//
-//##
-
-$panel-bg:                    #fff !default;
-$panel-body-padding:          15px !default;
-$panel-heading-padding:       10px 15px !default;
-$panel-footer-padding:        $panel-heading-padding !default;
-$panel-border-radius:         $border-radius-base !default;
-
-//** Border color for elements within panels
-$panel-inner-border:          #ddd !default;
-$panel-footer-bg:             #f5f5f5 !default;
-
-$panel-default-text:          $gray-dark !default;
-$panel-default-border:        #ddd !default;
-$panel-default-heading-bg:    #f5f5f5 !default;
-
-$panel-primary-text:          #fff !default;
-$panel-primary-border:        $brand-primary !default;
-$panel-primary-heading-bg:    $brand-primary !default;
-
-$panel-success-text:          $state-success-text !default;
-$panel-success-border:        $state-success-border !default;
-$panel-success-heading-bg:    $state-success-bg !default;
-
-$panel-info-text:             $state-info-text !default;
-$panel-info-border:           $state-info-border !default;
-$panel-info-heading-bg:       $state-info-bg !default;
-
-$panel-warning-text:          $state-warning-text !default;
-$panel-warning-border:        $state-warning-border !default;
-$panel-warning-heading-bg:    $state-warning-bg !default;
-
-$panel-danger-text:           $state-danger-text !default;
-$panel-danger-border:         $state-danger-border !default;
-$panel-danger-heading-bg:     $state-danger-bg !default;
-
-
-//== Thumbnails
-//
-//##
-
-//** Padding around the thumbnail image
-$thumbnail-padding:           4px !default;
-//** Thumbnail background color
-$thumbnail-bg:                $body-bg !default;
-//** Thumbnail border color
-$thumbnail-border:            #ddd !default;
-//** Thumbnail border radius
-$thumbnail-border-radius:     $border-radius-base !default;
-
-//** Custom text color for thumbnail captions
-$thumbnail-caption-color:     $text-color !default;
-//** Padding around the thumbnail caption
-$thumbnail-caption-padding:   9px !default;
-
-
-//== Wells
-//
-//##
-
-$well-bg:                     #f5f5f5 !default;
-$well-border:                 darken($well-bg, 7%) !default;
-
-
-//== Badges
-//
-//##
-
-$badge-color:                 #fff !default;
-//** Linked badge text color on hover
-$badge-link-hover-color:      #fff !default;
-$badge-bg:                    $gray-light !default;
-
-//** Badge text color in active nav link
-$badge-active-color:          $link-color !default;
-//** Badge background color in active nav link
-$badge-active-bg:             #fff !default;
-
-$badge-font-weight:           bold !default;
-$badge-line-height:           1 !default;
-$badge-border-radius:         10px !default;
-
-
-//== Breadcrumbs
-//
-//##
-
-$breadcrumb-padding-vertical:   8px !default;
-$breadcrumb-padding-horizontal: 15px !default;
-//** Breadcrumb background color
-$breadcrumb-bg:                 #f5f5f5 !default;
-//** Breadcrumb text color
-$breadcrumb-color:              #ccc !default;
-//** Text color of current page in the breadcrumb
-$breadcrumb-active-color:       $gray-light !default;
-//** Textual separator for between breadcrumb elements
-$breadcrumb-separator:          "/" !default;
-
-
-//== Carousel
-//
-//##
-
-$carousel-text-shadow:                        none !default;
-
-$carousel-control-color:                      #333 !default;
-$carousel-control-width:                      25% !default;
-$carousel-control-opacity:                    1 !default;
-$carousel-control-font-size:                  20px !default;
-
-$carousel-indicator-active-bg:                #333 !default;
-$carousel-indicator-border-color:             #333 !default;
-
-$carousel-caption-color:                      #333 !default;
-
-
-//== Close
-//
-//##
-
-$close-font-weight:           bold !default;
-$close-color:                 #000 !default;
-$close-text-shadow:           0 1px 0 #fff !default;
-
-
-//== Code
-//
-//##
-
-$code-color:                  #c7254e !default;
-$code-bg:                     #f9f2f4 !default;
-
-$kbd-color:                   #fff !default;
-$kbd-bg:                      #333 !default;
-
-$pre-bg:                      #f5f5f5 !default;
-$pre-color:                   $gray-dark !default;
-$pre-border-color:            #ccc !default;
-$pre-scrollable-max-height:   340px !default;
-
-
-//== Type
-//
-//##
-
-//** Horizontal offset for forms and lists.
-$component-offset-horizontal: 180px !default;
-//** Text muted color
-$text-muted:                  $gray-light !default;
-//** Abbreviations and acronyms border color
-$abbr-border-color:           $gray-light !default;
-//** Headings small color
-$headings-small-color:        $gray-light !default;
-//** Blockquote small color
-$blockquote-small-color:      $gray-light !default;
-//** Blockquote font size
-$blockquote-font-size:        ($font-size-base * 1.25) !default;
-//** Blockquote border color
-$blockquote-border-color:     $gray-lighter !default;
-//** Page header border color
-$page-header-border-color:    $gray-lighter !default;
-//** Width of horizontal description list titles
-$dl-horizontal-offset:        $component-offset-horizontal !default;
-//** Point at which .dl-horizontal becomes horizontal
-$dl-horizontal-breakpoint:    $grid-float-breakpoint !default;
-//** Horizontal line color.
-$hr-border:                   $gray-lighter !default;

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/src/main/js/public/stylesheets/_font-awesome-custom.scss
----------------------------------------------------------------------
diff --git a/modules/web-console/src/main/js/public/stylesheets/_font-awesome-custom.scss b/modules/web-console/src/main/js/public/stylesheets/_font-awesome-custom.scss
deleted file mode 100644
index 514acc2..0000000
--- a/modules/web-console/src/main/js/public/stylesheets/_font-awesome-custom.scss
+++ /dev/null
@@ -1,32 +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 '~font-awesome/scss/variables';
-
-$fa-font-path: 'https://maxcdn.bootstrapcdn.com/font-awesome/4.6.3/fonts';
-
-@import '~font-awesome/scss/mixins';
-@import '~font-awesome/scss/path';
-@import '~font-awesome/scss/core';
-@import '~font-awesome/scss/larger';
-@import '~font-awesome/scss/fixed-width';
-@import '~font-awesome/scss/list';
-@import '~font-awesome/scss/bordered-pulled';
-@import '~font-awesome/scss/animated';
-@import '~font-awesome/scss/rotated-flipped';
-@import '~font-awesome/scss/stacked';
-@import '~font-awesome/scss/icons';


[44/52] ignite git commit: Web Console beta-3.

Posted by ak...@apache.org.
http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/backend/app/agent.js
----------------------------------------------------------------------
diff --git a/modules/web-console/backend/app/agent.js b/modules/web-console/backend/app/agent.js
new file mode 100644
index 0000000..a1858fd
--- /dev/null
+++ b/modules/web-console/backend/app/agent.js
@@ -0,0 +1,753 @@
+/*
+ * 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.
+ */
+
+'use strict';
+
+// Fire me up!
+
+/**
+ * Module interaction with agents.
+ */
+module.exports = {
+    implements: 'agent-manager',
+    inject: ['require(lodash)', 'require(ws)', 'require(fs)', 'require(path)', 'require(jszip)', 'require(socket.io)', 'settings', 'mongo']
+};
+
+/**
+ * @param _
+ * @param fs
+ * @param ws
+ * @param path
+ * @param JSZip
+ * @param socketio
+ * @param settings
+ * @param mongo
+ * @returns {AgentManager}
+ */
+module.exports.factory = function(_, ws, fs, path, JSZip, socketio, settings, mongo) {
+    /**
+     *
+     */
+    class Command {
+        /**
+         * @param {Boolean} demo Is need run command on demo node.
+         * @param {String} name Command name.
+         */
+        constructor(demo, name) {
+            this._demo = demo;
+
+            /**
+             * Command name.
+             * @type {String}
+             */
+            this._name = name;
+
+            /**
+             * Command parameters.
+             * @type {Array.<String>}
+             */
+            this._params = [];
+        }
+
+        /**
+         * Add parameter to command.
+         * @param {string} key Parameter key.
+         * @param {Object} value Parameter value.
+         * @returns {Command}
+         */
+        addParam(key, value) {
+            this._params.push({key, value});
+
+            return this;
+        }
+    }
+
+    /**
+     * Connected agent descriptor.
+     */
+    class Agent {
+        /**
+         * @param {socketIo.Socket} socket - Agent socket for interaction.
+         */
+        constructor(socket) {
+            /**
+             * Agent socket for interaction.
+             *
+             * @type {socketIo.Socket}
+             * @private
+             */
+            this._socket = socket;
+        }
+
+        /**
+         * Send message to agent.
+         *
+         * @this {Agent}
+         * @param {String} event Command name.
+         * @param {Object} data Command params.
+         * @param {Function} [callback] on finish
+         */
+        _emit(event, data, callback) {
+            if (!this._socket.connected) {
+                if (callback)
+                    callback('org.apache.ignite.agent.AgentException: Connection is closed');
+
+                return;
+            }
+
+            this._socket.emit(event, data, callback);
+        }
+
+        /**
+         * Send message to agent.
+         *
+         * @param {String} event - Event name.
+         * @param {Object?} data - Transmitted data.
+         * @returns {Promise}
+         */
+        executeAgent(event, data) {
+            return new Promise((resolve, reject) =>
+                this._emit(event, data, (error, res) => {
+                    if (error)
+                        return reject(error);
+
+                    resolve(res);
+                })
+            );
+        }
+
+        /**
+         * Execute rest request on node.
+         *
+         * @param {Command} cmd - REST command.
+         * @return {Promise}
+         */
+        executeRest(cmd) {
+            const params = {cmd: cmd._name};
+
+            for (const param of cmd._params)
+                params[param.key] = param.value;
+
+            return new Promise((resolve, reject) => {
+                this._emit('node:rest', {uri: 'ignite', params, demo: cmd._demo, method: 'GET'}, (error, res) => {
+                    if (error)
+                        return reject(new Error(error));
+
+                    error = res.error;
+
+                    const code = res.code;
+
+                    if (code === 401)
+                        return reject(new Error('Agent failed to authenticate in grid. Please check agent\'s login and password or node port.'));
+
+                    if (code !== 200)
+                        return reject(new Error(error || 'Failed connect to node and execute REST command.'));
+
+                    try {
+                        const msg = JSON.parse(res.data);
+
+                        if (msg.successStatus === 0)
+                            return resolve(msg.response);
+
+                        if (msg.successStatus === 2)
+                            return reject(new Error('Agent failed to authenticate in grid. Please check agent\'s login and password or node port.'));
+
+                        reject(new Error(msg.error));
+                    }
+                    catch (e) {
+                        return reject(e);
+                    }
+                });
+            });
+        }
+
+        /**
+         * @param {String} driverPath
+         * @param {String} driverClass
+         * @param {String} url
+         * @param {Object} info
+         * @returns {Promise} Promise on list of tables (see org.apache.ignite.schema.parser.DbTable java class)
+         */
+        metadataSchemas(driverPath, driverClass, url, info) {
+            return this.executeAgent('schemaImport:schemas', {driverPath, driverClass, url, info});
+        }
+
+        /**
+         * @param {String} driverPath
+         * @param {String} driverClass
+         * @param {String} url
+         * @param {Object} info
+         * @param {Array} schemas
+         * @param {Boolean} tablesOnly
+         * @returns {Promise} Promise on list of tables (see org.apache.ignite.schema.parser.DbTable java class)
+         */
+        metadataTables(driverPath, driverClass, url, info, schemas, tablesOnly) {
+            return this.executeAgent('schemaImport:metadata', {driverPath, driverClass, url, info, schemas, tablesOnly});
+        }
+
+        /**
+         * @returns {Promise} Promise on list of jars from driver folder.
+         */
+        availableDrivers() {
+            return this.executeAgent('schemaImport:drivers');
+        }
+
+        /**
+         *
+         * @param {Boolean} demo Is need run command on demo node.
+         * @param {Boolean} attr Get attributes, if this parameter has value true. Default value: true.
+         * @param {Boolean} mtr Get metrics, if this parameter has value true. Default value: false.
+         * @returns {Promise}
+         */
+        topology(demo, attr, mtr) {
+            const cmd = new Command(demo, 'top')
+                .addParam('attr', attr !== false)
+                .addParam('mtr', !!mtr);
+
+            return this.executeRest(cmd);
+        }
+
+        /**
+         * @param {Boolean} demo Is need run command on demo node.
+         * @param {String} nid Node id.
+         * @param {String} cacheName Cache name.
+         * @param {String} query Query.
+         * @param {Boolean} local Flag whether to execute query locally.
+         * @param {int} pageSize Page size.
+         * @returns {Promise}
+         */
+        fieldsQuery(demo, nid, cacheName, query, local, pageSize) {
+            const cmd = new Command(demo, 'exe')
+                .addParam('name', 'org.apache.ignite.internal.visor.compute.VisorGatewayTask')
+                .addParam('p1', nid)
+                .addParam('p2', 'org.apache.ignite.internal.visor.query.VisorQueryTask')
+                .addParam('p3', 'org.apache.ignite.internal.visor.query.VisorQueryArg')
+                .addParam('p4', cacheName)
+                .addParam('p5', query)
+                .addParam('p6', local)
+                .addParam('p7', pageSize);
+
+            return this.executeRest(cmd);
+        }
+
+        /**
+         * @param {Boolean} demo Is need run command on demo node.
+         * @param {String} nid Node id.
+         * @param {int} queryId Query Id.
+         * @param {int} pageSize Page size.
+         * @returns {Promise}
+         */
+        queryFetch(demo, nid, queryId, pageSize) {
+            const cmd = new Command(demo, 'exe')
+                .addParam('name', 'org.apache.ignite.internal.visor.compute.VisorGatewayTask')
+                .addParam('p1', nid)
+                .addParam('p2', 'org.apache.ignite.internal.visor.query.VisorQueryNextPageTask')
+                .addParam('p3', 'org.apache.ignite.lang.IgniteBiTuple')
+                .addParam('p4', 'java.lang.String')
+                .addParam('p5', 'java.lang.Integer')
+                .addParam('p6', queryId)
+                .addParam('p7', pageSize);
+
+            return this.executeRest(cmd);
+        }
+
+        /**
+         * @param {Boolean} demo Is need run command on demo node.
+         * @param {String} nid Node id.
+         * @param {int} queryId Query Id.
+         * @returns {Promise}
+         */
+        queryClose(demo, nid, queryId) {
+            const cmd = new Command(demo, 'exe')
+                .addParam('name', 'org.apache.ignite.internal.visor.compute.VisorGatewayTask')
+                .addParam('p1', '')
+                .addParam('p2', 'org.apache.ignite.internal.visor.query.VisorQueryCleanupTask')
+                .addParam('p3', 'java.util.Map')
+                .addParam('p4', 'java.util.UUID')
+                .addParam('p5', 'java.util.Set')
+                .addParam('p6', `${nid}=${queryId}`);
+
+            return this.executeRest(cmd);
+        }
+
+        /**
+         * @param {Boolean} demo Is need run command on demo node.
+         * @param {String} cacheName Cache name.
+         * @returns {Promise}
+         */
+        metadata(demo, cacheName) {
+            const cmd = new Command(demo, 'metadata')
+                .addParam('cacheName', cacheName);
+
+            return this.executeRest(cmd);
+        }
+
+        /**
+         * @param {Boolean} demo Is need run command on demo node.
+         * @param {String} evtOrderKey Event order key, unique for tab instance.
+         * @param {String} evtThrottleCntrKey Event throttle counter key, unique for tab instance.
+         * @returns {Promise}
+         */
+        collect(demo, evtOrderKey, evtThrottleCntrKey) {
+            const cmd = new Command(demo, 'exe')
+                .addParam('name', 'org.apache.ignite.internal.visor.compute.VisorGatewayTask')
+                .addParam('p1', '')
+                .addParam('p2', 'org.apache.ignite.internal.visor.node.VisorNodeDataCollectorTask')
+                .addParam('p3', 'org.apache.ignite.internal.visor.node.VisorNodeDataCollectorTaskArg')
+                .addParam('p4', true)
+                .addParam('p5', 'CONSOLE_' + evtOrderKey)
+                .addParam('p6', evtThrottleCntrKey)
+                .addParam('p7', 10)
+                .addParam('p8', false);
+
+            return this.executeRest(cmd);
+        }
+
+        /**
+         * @param {Boolean} demo Is need run command on demo node.
+         * @param {String} nid Node id.
+         * @returns {Promise}
+         */
+        collectNodeConfiguration(demo, nid) {
+            const cmd = new Command(demo, 'exe')
+                .addParam('name', 'org.apache.ignite.internal.visor.compute.VisorGatewayTask')
+                .addParam('p1', nid)
+                .addParam('p2', 'org.apache.ignite.internal.visor.node.VisorNodeConfigurationCollectorTask')
+                .addParam('p3', 'java.lang.Void')
+                .addParam('p4', null);
+
+            return this.executeRest(cmd);
+        }
+
+        /**
+         * @param {Boolean} demo Is need run command on demo node.
+         * @param {String} nid Node id.
+         * @param {Array.<String>} caches Caches deployment IDs to collect configuration.
+         * @returns {Promise}
+         */
+        collectCacheConfigurations(demo, nid, caches) {
+            const cmd = new Command(demo, 'exe')
+                .addParam('name', 'org.apache.ignite.internal.visor.compute.VisorGatewayTask')
+                .addParam('p1', nid)
+                .addParam('p2', 'org.apache.ignite.internal.visor.cache.VisorCacheConfigurationCollectorTask')
+                .addParam('p3', 'java.util.Collection')
+                .addParam('p4', 'org.apache.ignite.lang.IgniteUuid')
+                .addParam('p5', caches);
+
+            return this.executeRest(cmd);
+        }
+
+        /**
+         * @param {Boolean} demo Is need run command on demo node.
+         * @param {String} nid Node id.
+         * @param {String} cacheName Cache name.
+         * @returns {Promise}
+         */
+        cacheClear(demo, nid, cacheName) {
+            const cmd = new Command(demo, 'exe')
+                .addParam('name', 'org.apache.ignite.internal.visor.compute.VisorGatewayTask')
+                .addParam('p1', nid)
+                .addParam('p2', 'org.apache.ignite.internal.visor.cache.VisorCacheClearTask')
+                .addParam('p3', 'java.lang.String')
+                .addParam('p4', cacheName);
+
+            return this.executeRest(cmd);
+        }
+
+        /**
+         * @param {Boolean} demo Is need run command on demo node.
+         * @param {Array.<String>} nids Node ids.
+         * @param {Boolean} near true if near cache should be started.
+         * @param {String} cacheName Name for near cache.
+         * @param {String} cfg Cache XML configuration.
+         * @returns {Promise}
+         */
+        cacheStart(demo, nids, near, cacheName, cfg) {
+            const cmd = new Command(demo, 'exe')
+                .addParam('name', 'org.apache.ignite.internal.visor.compute.VisorGatewayTask')
+                .addParam('p1', nids)
+                .addParam('p2', 'org.apache.ignite.internal.visor.cache.VisorCacheStartTask')
+                .addParam('p3', 'org.apache.ignite.internal.visor.cache.VisorCacheStartTask$VisorCacheStartArg')
+                .addParam('p4', near)
+                .addParam('p5', cacheName)
+                .addParam('p6', cfg);
+
+            return this.executeRest(cmd);
+        }
+
+        /**
+         * @param {Boolean} demo Is need run command on demo node.
+         * @param {String} nid Node id.
+         * @param {String} cacheName Cache name.
+         * @returns {Promise}
+         */
+        cacheStop(demo, nid, cacheName) {
+            const cmd = new Command(demo, 'exe')
+                .addParam('name', 'org.apache.ignite.internal.visor.compute.VisorGatewayTask')
+                .addParam('p1', nid)
+                .addParam('p2', 'org.apache.ignite.internal.visor.cache.VisorCacheStopTask')
+                .addParam('p3', 'java.lang.String')
+                .addParam('p4', cacheName);
+
+            return this.executeRest(cmd);
+        }
+
+        /**
+         * @param {Boolean} demo Is need run command on demo node.
+         * @param {String} nid Node id.
+         * @param {String} cacheName Cache name.
+         * @returns {Promise}
+         */
+        cacheResetMetrics(demo, nid, cacheName) {
+            const cmd = new Command(demo, 'exe')
+                .addParam('name', 'org.apache.ignite.internal.visor.compute.VisorGatewayTask')
+                .addParam('p1', nid)
+                .addParam('p2', 'org.apache.ignite.internal.visor.cache.VisorCacheResetMetricsTask')
+                .addParam('p3', 'java.lang.String')
+                .addParam('p4', cacheName);
+
+            return this.executeRest(cmd);
+        }
+
+        /**
+         * @param {Boolean} demo Is need run command on demo node.
+         * @param {String} nid Node id.
+         * @param {String} cacheNames Cache names separated by comma.
+         * @returns {Promise}
+         */
+        cacheSwapBackups(demo, nid, cacheNames) {
+            const cmd = new Command(demo, 'exe')
+                .addParam('name', 'org.apache.ignite.internal.visor.compute.VisorGatewayTask')
+                .addParam('p1', nid)
+                .addParam('p2', 'org.apache.ignite.internal.visor.cache.VisorCacheSwapBackupsTask')
+                .addParam('p3', 'java.util.Set')
+                .addParam('p4', 'java.lang.String')
+                .addParam('p5', cacheNames);
+
+            return this.executeRest(cmd);
+        }
+
+        /**
+         * @param {Boolean} demo Is need run command on demo node.
+         * @param {String} nids Node ids.
+         * @returns {Promise}
+         */
+        gc(demo, nids) {
+            const cmd = new Command(demo, 'exe')
+                .addParam('name', 'org.apache.ignite.internal.visor.compute.VisorGatewayTask')
+                .addParam('p1', nids)
+                .addParam('p2', 'org.apache.ignite.internal.visor.node.VisorNodeGcTask')
+                .addParam('p3', 'java.lang.Void');
+
+            return this.executeRest(cmd);
+        }
+
+        /**
+         * @param {Boolean} demo Is need run command on demo node.
+         * @param {String} taskNid node that is not node we want to ping.
+         * @param {String} nid Id of the node to ping.
+         * @returns {Promise}
+         */
+        ping(demo, taskNid, nid) {
+            const cmd = new Command(demo, 'exe')
+                .addParam('name', 'org.apache.ignite.internal.visor.compute.VisorGatewayTask')
+                .addParam('p1', taskNid)
+                .addParam('p2', 'org.apache.ignite.internal.visor.node.VisorNodePingTask')
+                .addParam('p3', 'java.util.UUID')
+                .addParam('p4', nid);
+
+            return this.executeRest(cmd);
+        }
+
+        /**
+         * @param {Boolean} demo Is need run command on demo node.
+         * @param {String} nid Id of the node to get thread dump.
+         * @returns {Promise}
+         */
+        threadDump(demo, nid) {
+            const cmd = new Command(demo, 'exe')
+                .addParam('name', 'org.apache.ignite.internal.visor.compute.VisorGatewayTask')
+                .addParam('p1', nid)
+                .addParam('p2', 'org.apache.ignite.internal.visor.debug.VisorThreadDumpTask')
+                .addParam('p3', 'java.lang.Void');
+
+            return this.executeRest(cmd);
+        }
+    }
+
+    /**
+     * Connected agents manager.
+     */
+    class AgentManager {
+        /**
+         * @constructor
+         */
+        constructor() {
+            /**
+             * Connected agents by user id.
+             * @type {Object.<ObjectId, Array.<Agent>>}
+             */
+            this._agents = {};
+
+            /**
+             * Connected browsers by user id.
+             * @type {Object.<ObjectId, Array.<Socket>>}
+             */
+            this._browsers = {};
+
+            const agentArchives = fs.readdirSync(settings.agent.dists)
+                .filter((file) => path.extname(file) === '.zip');
+
+            /**
+             * Supported agents distribution.
+             * @type {Object.<String, String>}
+             */
+            this.supportedAgents = {};
+
+            const jarFilter = (file) => path.extname(file) === '.jar';
+
+            const agentsPromises = _.map(agentArchives, (fileName) => {
+                const filePath = path.join(settings.agent.dists, fileName);
+
+                return JSZip.loadAsync(fs.readFileSync(filePath))
+                    .then((zip) => {
+                        const jarPath = _.find(_.keys(zip.files), jarFilter);
+
+                        return JSZip.loadAsync(zip.files[jarPath].async('nodebuffer'))
+                            .then((jar) => jar.files['META-INF/MANIFEST.MF'].async('string'))
+                            .then((lines) => lines.trim()
+                                .split(/\s*\n+\s*/)
+                                .map((line, r) => {
+                                    r = line.split(/\s*:\s*/);
+
+                                    this[r[0]] = r[1];
+
+                                    return this;
+                                }, {})[0])
+                            .then((manifest) => {
+                                const ver = manifest['Implementation-Version'];
+                                const buildTime = manifest['Build-Time'];
+
+                                if (ver && buildTime)
+                                    return { fileName, filePath, ver, buildTime };
+                            });
+                    });
+            });
+
+            Promise.all(agentsPromises)
+                .then((agents) => {
+                    this.supportedAgents = _.keyBy(_.remove(agents, null), 'ver');
+
+                    const latest = _.head(Object.keys(this.supportedAgents).sort((a, b) => {
+                        const aParts = a.split('.');
+                        const bParts = b.split('.');
+
+                        for (let i = 0; i < aParts.length; ++i) {
+                            if (bParts.length === i)
+                                return 1;
+
+                            if (aParts[i] === aParts[i])
+                                continue;
+
+                            return aParts[i] > bParts[i] ? 1 : -1;
+                        }
+                    }));
+
+                    // Latest version of agent distribution.
+                    if (latest)
+                        this.supportedAgents.latest = this.supportedAgents[latest];
+                });
+        }
+
+        attachLegacy(server) {
+            const wsSrv = new ws.Server({server});
+
+            wsSrv.on('connection', (_wsClient) => {
+                _wsClient.send(JSON.stringify({
+                    method: 'authResult',
+                    args: ['You are using an older version of the agent. Please reload agent archive']
+                }));
+            });
+        }
+
+        /**
+         * @param {http.Server|https.Server} srv Server instance that we want to attach agent handler.
+         */
+        attach(srv) {
+            if (this._server)
+                throw 'Agent server already started!';
+
+            this._server = srv;
+
+            /**
+             * @type {socketIo.Server}
+             */
+            this._socket = socketio(this._server);
+
+            this._socket.on('connection', (socket) => {
+                socket.on('agent:auth', (data, cb) => {
+                    if (!_.isEmpty(this.supportedAgents)) {
+                        const ver = data.ver;
+                        const bt = data.bt;
+
+                        if (_.isEmpty(ver) || _.isEmpty(bt) || _.isEmpty(this.supportedAgents[ver]) ||
+                            this.supportedAgents[ver].buildTime > bt)
+                            return cb('You are using an older version of the agent. Please reload agent archive');
+                    }
+
+                    const tokens = data.tokens;
+
+                    mongo.Account.find({token: {$in: tokens}}, '_id token').lean().exec()
+                        .then((accounts) => {
+                            if (!accounts.length)
+                                return cb('Agent is failed to authenticate. Please check agent\'s token(s)');
+
+                            const agent = new Agent(socket);
+
+                            const accountIds = _.map(accounts, (account) => account._id);
+
+                            socket.on('disconnect', () => this._agentDisconnected(accountIds, agent));
+
+                            this._agentConnected(accountIds, agent);
+
+                            const missedTokens = _.difference(tokens, _.map(accounts, (account) => account.token));
+
+                            if (missedTokens.length) {
+                                agent._emit('agent:warning',
+                                    `Failed to authenticate with token(s): ${missedTokens.join(', ')}.`);
+                            }
+
+                            cb();
+                        })
+                        // TODO IGNITE-1379 send error to web master.
+                        .catch(() => cb('Agent is failed to authenticate. Please check agent\'s tokens'));
+                });
+            });
+        }
+
+        /**
+         * @param {ObjectId} accountId
+         * @param {Socket} socket
+         * @returns {int} Connected agent count.
+         */
+        addAgentListener(accountId, socket) {
+            let sockets = this._browsers[accountId];
+
+            if (!sockets)
+                this._browsers[accountId] = sockets = [];
+
+            sockets.push(socket);
+
+            const agents = this._agents[accountId];
+
+            return agents ? agents.length : 0;
+        }
+
+        /**
+         * @param {ObjectId} accountId.
+         * @param {Socket} socket.
+         * @returns {int} connected agent count.
+         */
+        removeAgentListener(accountId, socket) {
+            const sockets = this._browsers[accountId];
+
+            _.pull(sockets, socket);
+        }
+
+        /**
+         * @param {ObjectId} accountId
+         * @returns {Promise.<Agent>}
+         */
+        findAgent(accountId) {
+            if (!this._server)
+                return Promise.reject(new Error('Agent server not started yet!'));
+
+            const agents = this._agents[accountId];
+
+            if (!agents || agents.length === 0)
+                return Promise.reject(new Error('Failed to connect to agent'));
+
+            return Promise.resolve(agents[0]);
+        }
+
+        /**
+         * Close connections for all user agents.
+         * @param {ObjectId} accountId
+         * @param {String} oldToken
+         */
+        close(accountId, oldToken) {
+            if (!this._server)
+                return;
+
+            const agentsForClose = this._agents[accountId];
+
+            const agentsForWarning = _.clone(agentsForClose);
+
+            this._agents[accountId] = [];
+
+            _.forEach(this._agents, (sockets) => _.pullAll(agentsForClose, sockets));
+
+            _.pullAll(agentsForWarning, agentsForClose);
+
+            const msg = `Security token has been reset: ${oldToken}`;
+
+            _.forEach(agentsForWarning, (socket) => socket._emit('agent:warning', msg));
+
+            _.forEach(agentsForClose, (socket) => socket._emit('agent:close', msg));
+
+            _.forEach(this._browsers[accountId], (socket) => socket.emit('agent:count', {count: 0}));
+        }
+
+        /**
+         * @param {ObjectId} accountIds
+         * @param {Agent} agent
+         */
+        _agentConnected(accountIds, agent) {
+            _.forEach(accountIds, (accountId) => {
+                let agents = this._agents[accountId];
+
+                if (!agents)
+                    this._agents[accountId] = agents = [];
+
+                agents.push(agent);
+
+                const sockets = this._browsers[accountId];
+
+                _.forEach(sockets, (socket) => socket.emit('agent:count', {count: agents.length}));
+            });
+        }
+
+        /**
+         * @param {ObjectId} accountIds
+         * @param {Agent} agent
+         */
+        _agentDisconnected(accountIds, agent) {
+            _.forEach(accountIds, (accountId) => {
+                const agents = this._agents[accountId];
+
+                if (agents && agents.length)
+                    _.pull(agents, agent);
+
+                const sockets = this._browsers[accountId];
+
+                _.forEach(sockets, (socket) => socket.emit('agent:count', {count: agents.length}));
+            });
+        }
+    }
+
+    return new AgentManager();
+};

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/backend/app/app.js
----------------------------------------------------------------------
diff --git a/modules/web-console/backend/app/app.js b/modules/web-console/backend/app/app.js
new file mode 100644
index 0000000..1bbfd2c
--- /dev/null
+++ b/modules/web-console/backend/app/app.js
@@ -0,0 +1,61 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+'use strict';
+
+// Fire me up!
+
+module.exports = {
+    implements: 'app',
+    inject: ['require(express)', 'configure', 'routes']
+};
+
+module.exports.factory = function(Express, configure, routes) {
+    return {
+        /**
+         * @param {Server} srv
+         */
+        listen: (srv) => {
+            const app = new Express();
+
+            configure.express(app);
+
+            routes.register(app);
+
+            // Catch 404 and forward to error handler.
+            app.use((req, res, next) => {
+                const err = new Error('Not Found: ' + req.originalUrl);
+
+                err.status = 404;
+
+                next(err);
+            });
+
+            // Production error handler: no stacktraces leaked to user.
+            app.use((err, req, res) => {
+                res.status(err.status || 500);
+
+                res.render('error', {
+                    message: err.message,
+                    error: {}
+                });
+            });
+
+            srv.addListener('request', app);
+        }
+    };
+};

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/backend/app/browser.js
----------------------------------------------------------------------
diff --git a/modules/web-console/backend/app/browser.js b/modules/web-console/backend/app/browser.js
new file mode 100644
index 0000000..3256b6a
--- /dev/null
+++ b/modules/web-console/backend/app/browser.js
@@ -0,0 +1,404 @@
+/*
+ * 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.
+ */
+
+'use strict';
+
+// Fire me up!
+
+/**
+ * Module interaction with browsers.
+ */
+module.exports = {
+    implements: 'browser-manager',
+    inject: ['require(lodash)', 'require(socket.io)', 'agent-manager', 'configure']
+};
+
+module.exports.factory = (_, socketio, agentMgr, configure) => {
+    const _errorToJson = (err) => {
+        return {
+            message: err.message || err,
+            code: err.code || 1
+        };
+    };
+
+    return {
+        attach: (server) => {
+            const io = socketio(server);
+
+            configure.socketio(io);
+
+            io.sockets.on('connection', (socket) => {
+                const user = socket.request.user;
+
+                const demo = socket.request._query.IgniteDemoMode === 'true';
+
+                const accountId = () => user._id;
+
+                // Return available drivers to browser.
+                socket.on('schemaImport:drivers', (cb) => {
+                    agentMgr.findAgent(accountId())
+                        .then((agent) => agent.availableDrivers())
+                        .then((drivers) => cb(null, drivers))
+                        .catch((err) => cb(_errorToJson(err)));
+                });
+
+                // Return schemas from database to browser.
+                socket.on('schemaImport:schemas', (preset, cb) => {
+                    agentMgr.findAgent(accountId())
+                        .then((agent) => {
+                            const jdbcInfo = {user: preset.user, password: preset.password};
+
+                            return agent.metadataSchemas(preset.jdbcDriverJar, preset.jdbcDriverClass, preset.jdbcUrl, jdbcInfo);
+                        })
+                        .then((schemas) => cb(null, schemas))
+                        .catch((err) => cb(_errorToJson(err)));
+                });
+
+                // Return tables from database to browser.
+                socket.on('schemaImport:tables', (preset, cb) => {
+                    agentMgr.findAgent(accountId())
+                        .then((agent) => {
+                            const jdbcInfo = {user: preset.user, password: preset.password};
+
+                            return agent.metadataTables(preset.jdbcDriverJar, preset.jdbcDriverClass, preset.jdbcUrl, jdbcInfo,
+                                preset.schemas, preset.tablesOnly);
+                        })
+                        .then((tables) => cb(null, tables))
+                        .catch((err) => cb(_errorToJson(err)));
+                });
+
+                // Return topology command result from grid to browser.
+                socket.on('node:topology', (attr, mtr, cb) => {
+                    agentMgr.findAgent(accountId())
+                        .then((agent) => agent.topology(demo, attr, mtr))
+                        .then((clusters) => cb(null, clusters))
+                        .catch((err) => cb(_errorToJson(err)));
+                });
+
+                // Close query on node.
+                socket.on('node:query:close', (nid, queryId, cb) => {
+                    agentMgr.findAgent(accountId())
+                        .then((agent) => agent.queryClose(demo, nid, queryId))
+                        .then(() => cb())
+                        .catch((err) => cb(_errorToJson(err)));
+                });
+
+                // Execute query on node and return first page to browser.
+                socket.on('node:query', (nid, cacheName, query, local, pageSize, cb) => {
+                    agentMgr.findAgent(accountId())
+                        .then((agent) => agent.fieldsQuery(demo, nid, cacheName, query, local, pageSize))
+                        .then((res) => cb(null, res))
+                        .catch((err) => cb(_errorToJson(err)));
+                });
+
+                // Fetch next page for query and return result to browser.
+                socket.on('node:query:fetch', (nid, queryId, pageSize, cb) => {
+                    agentMgr.findAgent(accountId())
+                        .then((agent) => agent.queryFetch(demo, nid, queryId, pageSize))
+                        .then((res) => cb(null, res))
+                        .catch((err) => cb(_errorToJson(err)));
+                });
+
+                // Execute query on node and return full result to browser.
+                socket.on('node:query:getAll', (nid, cacheName, query, local, cb) => {
+                    // Set page size for query.
+                    const pageSize = 1024;
+
+                    agentMgr.findAgent(accountId())
+                        .then((agent) => {
+                            const firstPage = agent.fieldsQuery(demo, nid, cacheName, query, local, pageSize)
+                                .then(({result}) => {
+                                    if (result.key)
+                                        return Promise.reject(result.key);
+
+                                    return result.value;
+                                });
+
+                            const fetchResult = (acc) => {
+                                if (!acc.hasMore)
+                                    return acc;
+
+                                return agent.queryFetch(demo, acc.responseNodeId, acc.queryId, pageSize)
+                                    .then((res) => {
+                                        acc.rows = acc.rows.concat(res.rows);
+
+                                        acc.hasMore = res.hasMore;
+
+                                        return fetchResult(acc);
+                                    });
+                            };
+
+                            return firstPage
+                                .then(fetchResult);
+                        })
+                        .then((res) => cb(null, res))
+                        .catch((err) => cb(_errorToJson(err)));
+                });
+
+                // Return cache metadata from all nodes in grid.
+                socket.on('node:cache:metadata', (cacheName, cb) => {
+                    agentMgr.findAgent(accountId())
+                        .then((agent) => agent.metadata(demo, cacheName))
+                        .then((caches) => {
+                            let types = [];
+
+                            const _compact = (className) => {
+                                return className.replace('java.lang.', '').replace('java.util.', '').replace('java.sql.', '');
+                            };
+
+                            const _typeMapper = (meta, typeName) => {
+                                const maskedName = _.isEmpty(meta.cacheName) ? '<default>' : meta.cacheName;
+
+                                let fields = meta.fields[typeName];
+
+                                let columns = [];
+
+                                for (const fieldName in fields) {
+                                    if (fields.hasOwnProperty(fieldName)) {
+                                        const fieldClass = _compact(fields[fieldName]);
+
+                                        columns.push({
+                                            type: 'field',
+                                            name: fieldName,
+                                            clazz: fieldClass,
+                                            system: fieldName === '_KEY' || fieldName === '_VAL',
+                                            cacheName: meta.cacheName,
+                                            typeName,
+                                            maskedName
+                                        });
+                                    }
+                                }
+
+                                const indexes = [];
+
+                                for (const index of meta.indexes[typeName]) {
+                                    fields = [];
+
+                                    for (const field of index.fields) {
+                                        fields.push({
+                                            type: 'index-field',
+                                            name: field,
+                                            order: index.descendings.indexOf(field) < 0,
+                                            unique: index.unique,
+                                            cacheName: meta.cacheName,
+                                            typeName,
+                                            maskedName
+                                        });
+                                    }
+
+                                    if (fields.length > 0) {
+                                        indexes.push({
+                                            type: 'index',
+                                            name: index.name,
+                                            children: fields,
+                                            cacheName: meta.cacheName,
+                                            typeName,
+                                            maskedName
+                                        });
+                                    }
+                                }
+
+                                columns = _.sortBy(columns, 'name');
+
+                                if (!_.isEmpty(indexes)) {
+                                    columns = columns.concat({
+                                        type: 'indexes',
+                                        name: 'Indexes',
+                                        cacheName: meta.cacheName,
+                                        typeName,
+                                        maskedName,
+                                        children: indexes
+                                    });
+                                }
+
+                                return {
+                                    type: 'type',
+                                    cacheName: meta.cacheName || '',
+                                    typeName,
+                                    maskedName,
+                                    children: columns
+                                };
+                            };
+
+                            for (const meta of caches) {
+                                const cacheTypes = meta.types.map(_typeMapper.bind(null, meta));
+
+                                if (!_.isEmpty(cacheTypes))
+                                    types = types.concat(cacheTypes);
+                            }
+
+                            return cb(null, types);
+                        })
+                        .catch((err) => cb(_errorToJson(err)));
+                });
+
+                // Fetch next page for query and return result to browser.
+                socket.on('node:visor:collect', (evtOrderKey, evtThrottleCntrKey, cb) => {
+                    agentMgr.findAgent(accountId())
+                        .then((agent) => agent.collect(demo, evtOrderKey, evtThrottleCntrKey))
+                        .then((data) => {
+                            if (data.finished)
+                                return cb(null, data.result);
+
+                            cb(_errorToJson(data.error));
+                        })
+                        .catch((err) => cb(_errorToJson(err)));
+                });
+
+                // Gets node configuration for specified node.
+                socket.on('node:configuration', (nid, cb) => {
+                    agentMgr.findAgent(accountId())
+                        .then((agent) => agent.collectNodeConfiguration(demo, nid))
+                        .then((data) => {
+                            if (data.finished)
+                                return cb(null, data.result);
+
+                            cb(_errorToJson(data.error));
+                        })
+                        .catch((err) => cb(_errorToJson(err)));
+                });
+
+                // Gets cache configurations for specified node and caches deployment IDs.
+                socket.on('cache:configuration', (nid, caches, cb) => {
+                    agentMgr.findAgent(accountId())
+                        .then((agent) => agent.collectCacheConfigurations(demo, nid, caches))
+                        .then((data) => {
+                            if (data.finished)
+                                return cb(null, data.result);
+
+                            cb(_errorToJson(data.error));
+                        })
+                        .catch((err) => cb(_errorToJson(err)));
+                });
+
+                // Swap backups specified caches on specified node and return result to browser.
+                socket.on('node:cache:swap:backups', (nid, cacheNames, cb) => {
+                    agentMgr.findAgent(accountId())
+                        .then((agent) => agent.cacheSwapBackups(demo, nid, cacheNames))
+                        .then((data) => {
+                            if (data.finished)
+                                return cb(null, data.result);
+
+                            cb(_errorToJson(data.error));
+                        })
+                        .catch((err) => cb(_errorToJson(err)));
+                });
+
+                // Reset metrics specified cache on specified node and return result to browser.
+                socket.on('node:cache:reset:metrics', (nid, cacheName, cb) => {
+                    agentMgr.findAgent(accountId())
+                        .then((agent) => agent.cacheResetMetrics(demo, nid, cacheName))
+                        .then((data) => {
+                            if (data.finished)
+                                return cb(null, data.result);
+
+                            cb(_errorToJson(data.error));
+                        })
+                        .catch((err) => cb(_errorToJson(err)));
+                });
+
+                // Clear specified cache on specified node and return result to browser.
+                socket.on('node:cache:clear', (nid, cacheName, cb) => {
+                    agentMgr.findAgent(accountId())
+                        .then((agent) => agent.cacheClear(demo, nid, cacheName))
+                        .then((data) => {
+                            if (data.finished)
+                                return cb(null, data.result);
+
+                            cb(_errorToJson(data.error));
+                        })
+                        .catch((err) => cb(_errorToJson(err)));
+                });
+
+                // Start specified cache and return result to browser.
+                socket.on('node:cache:start', (nids, near, cacheName, cfg, cb) => {
+                    agentMgr.findAgent(accountId())
+                        .then((agent) => agent.cacheStart(demo, nids, near, cacheName, cfg))
+                        .then((data) => {
+                            if (data.finished)
+                                return cb(null, data.result);
+
+                            cb(_errorToJson(data.error));
+                        })
+                        .catch((err) => cb(_errorToJson(err)));
+                });
+
+                // Stop specified cache on specified node and return result to browser.
+                socket.on('node:cache:stop', (nid, cacheName, cb) => {
+                    agentMgr.findAgent(accountId())
+                        .then((agent) => agent.cacheStop(demo, nid, cacheName))
+                        .then((data) => {
+                            if (data.finished)
+                                return cb(null, data.result);
+
+                            cb(_errorToJson(data.error));
+                        })
+                        .catch((err) => cb(_errorToJson(err)));
+                });
+
+
+                // Ping node and return result to browser.
+                socket.on('node:ping', (taskNid, nid, cb) => {
+                    agentMgr.findAgent(accountId())
+                        .then((agent) => agent.ping(demo, taskNid, nid))
+                        .then((data) => {
+                            if (data.finished)
+                                return cb(null, data.result);
+
+                            cb(_errorToJson(data.error));
+                        })
+                        .catch((err) => cb(_errorToJson(err)));
+                });
+
+                // GC node and return result to browser.
+                socket.on('node:gc', (nids, cb) => {
+                    agentMgr.findAgent(accountId())
+                        .then((agent) => agent.gc(demo, nids))
+                        .then((data) => {
+                            if (data.finished)
+                                return cb(null, data.result);
+
+                            cb(_errorToJson(data.error));
+                        })
+                        .catch((err) => cb(_errorToJson(err)));
+                });
+
+                // GC node and return result to browser.
+                socket.on('node:thread:dump', (nid, cb) => {
+                    agentMgr.findAgent(accountId())
+                        .then((agent) => agent.threadDump(demo, nid))
+                        .then((data) => {
+                            if (data.finished)
+                                return cb(null, data.result);
+
+                            cb(_errorToJson(data.error));
+                        })
+                        .catch((err) => cb(_errorToJson(err)));
+                });
+
+                const count = agentMgr.addAgentListener(user._id, socket);
+
+                socket.emit('agent:count', {count});
+            });
+
+            // Handle browser disconnect event.
+            io.sockets.on('disconnect', (socket) =>
+                agentMgr.removeAgentListener(socket.client.request.user._id, socket)
+            );
+        }
+    };
+};

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/backend/app/configure.js
----------------------------------------------------------------------
diff --git a/modules/web-console/backend/app/configure.js b/modules/web-console/backend/app/configure.js
new file mode 100644
index 0000000..7624bdd
--- /dev/null
+++ b/modules/web-console/backend/app/configure.js
@@ -0,0 +1,86 @@
+/*
+ * 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.
+ */
+
+'use strict';
+
+// Fire me up!
+
+/**
+ * Module for configuration express and websocket server.
+ */
+module.exports = {
+    implements: 'configure',
+    inject: ['require(lodash)', 'require(morgan)', 'require(cookie-parser)', 'require(body-parser)',
+        'require(express-session)', 'require(connect-mongo)', 'require(passport)', 'require(passport.socketio)', 'settings', 'mongo', 'middlewares:*']
+};
+
+module.exports.factory = function(_, logger, cookieParser, bodyParser, session, connectMongo, passport, passportSocketIo, settings, mongo, apis) {
+    const _sessionStore = new (connectMongo(session))({mongooseConnection: mongo.connection});
+
+    return {
+        express: (app) => {
+            app.use(logger('dev', {
+                skip: (req, res) => res.statusCode < 400
+            }));
+
+            _.forEach(apis, (api) => app.use(api));
+
+            app.use(cookieParser(settings.sessionSecret));
+
+            app.use(bodyParser.json({limit: '50mb'}));
+            app.use(bodyParser.urlencoded({limit: '50mb', extended: true}));
+
+            app.use(session({
+                secret: settings.sessionSecret,
+                resave: false,
+                saveUninitialized: true,
+                unset: 'destroy',
+                cookie: {
+                    expires: new Date(Date.now() + settings.cookieTTL),
+                    maxAge: settings.cookieTTL
+                },
+                store: _sessionStore
+            }));
+
+            app.use(passport.initialize());
+            app.use(passport.session());
+
+            passport.serializeUser(mongo.Account.serializeUser());
+            passport.deserializeUser(mongo.Account.deserializeUser());
+
+            passport.use(mongo.Account.createStrategy());
+        },
+        socketio: (io) => {
+            const _onAuthorizeSuccess = (data, accept) => {
+                accept(null, true);
+            };
+
+            const _onAuthorizeFail = (data, message, error, accept) => {
+                accept(null, false);
+            };
+
+            io.use(passportSocketIo.authorize({
+                cookieParser,
+                key: 'connect.sid', // the name of the cookie where express/connect stores its session_id
+                secret: settings.sessionSecret, // the session_secret to parse the cookie
+                store: _sessionStore, // we NEED to use a sessionstore. no memorystore please
+                success: _onAuthorizeSuccess, // *optional* callback on success - read more below
+                fail: _onAuthorizeFail // *optional* callback on fail/error - read more below
+            }));
+        }
+    };
+};

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/backend/app/index.js
----------------------------------------------------------------------
diff --git a/modules/web-console/backend/app/index.js b/modules/web-console/backend/app/index.js
new file mode 100644
index 0000000..5796318
--- /dev/null
+++ b/modules/web-console/backend/app/index.js
@@ -0,0 +1,116 @@
+/*
+ * 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.
+ */
+
+'use strict';
+
+import fs from 'fs';
+import path from 'path';
+import http from 'http';
+import https from 'https';
+
+const igniteModules = process.env.IGNITE_MODULES || './ignite_modules';
+
+let injector;
+
+try {
+    const igniteModulesInjector = path.resolve(path.join(igniteModules, 'backend', 'injector.js'));
+
+    fs.accessSync(igniteModulesInjector, fs.F_OK);
+
+    injector = require(igniteModulesInjector);
+} catch (ignore) {
+    injector = require(path.join(__dirname, '../injector'));
+}
+
+/**
+ * Event listener for HTTP server "error" event.
+ */
+const _onError = (port, error) => {
+    if (error.syscall !== 'listen')
+        throw error;
+
+    const 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.
+ */
+const _onListening = (addr) => {
+    const bind = typeof addr === 'string' ? 'pipe ' + addr : 'port ' + addr.port;
+
+    console.log('Start listening on ' + bind);
+};
+
+Promise.all([injector('settings'), injector('app'), injector('agent-manager'), injector('browser-manager')])
+    .then(([settings, app, agentMgr, browserMgr]) => {
+        // Start rest server.
+        const server = settings.server.SSLOptions
+            ? https.createServer(settings.server.SSLOptions) : http.createServer();
+
+        server.listen(settings.server.port);
+        server.on('error', _onError.bind(null, settings.server.port));
+        server.on('listening', _onListening.bind(null, server.address()));
+
+        app.listen(server);
+        browserMgr.attach(server);
+
+        // Start legacy agent server for reject connection with message.
+        if (settings.agent.legacyPort) {
+            const agentLegacySrv = settings.agent.SSLOptions
+                ? https.createServer(settings.agent.SSLOptions) : http.createServer();
+
+            agentLegacySrv.listen(settings.agent.legacyPort);
+            agentLegacySrv.on('error', _onError.bind(null, settings.agent.legacyPort));
+            agentLegacySrv.on('listening', _onListening.bind(null, agentLegacySrv.address()));
+
+            agentMgr.attachLegacy(agentLegacySrv);
+        }
+
+        // Start agent server.
+        const agentServer = settings.agent.SSLOptions
+            ? https.createServer(settings.agent.SSLOptions) : http.createServer();
+
+        agentServer.listen(settings.agent.port);
+        agentServer.on('error', _onError.bind(null, settings.agent.port));
+        agentServer.on('listening', _onListening.bind(null, agentServer.address()));
+
+        agentMgr.attach(agentServer);
+
+        // Used for automated test.
+        if (process.send)
+            process.send('running');
+    }).catch((err) => {
+        console.error(err);
+
+        process.exit(1);
+    });

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/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
new file mode 100644
index 0000000..7fe39f0
--- /dev/null
+++ b/modules/web-console/backend/app/mongo.js
@@ -0,0 +1,673 @@
+/*
+ * 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.
+ */
+
+'use strict';
+
+// Fire me up!
+
+/**
+ * Module mongo schema.
+ */
+module.exports = {
+    implements: 'mongo',
+    inject: ['require(passport-local-mongoose)', 'settings', 'ignite_modules/mongo:*', 'require(mongoose)']
+};
+
+module.exports.factory = function(passportMongo, settings, pluginMongo, mongoose) {
+    // Use native promises
+    mongoose.Promise = global.Promise;
+
+    // Connect to mongoDB database.
+    mongoose.connect(settings.mongoUrl, {server: {poolSize: 4}});
+
+    const Schema = mongoose.Schema;
+    const ObjectId = mongoose.Schema.Types.ObjectId;
+    const result = { connection: mongoose.connection };
+
+    result.ObjectId = ObjectId;
+
+    // Define Account schema.
+    const AccountSchema = new Schema({
+        firstName: String,
+        lastName: String,
+        email: String,
+        company: String,
+        country: String,
+        lastLogin: Date,
+        admin: Boolean,
+        token: String,
+        resetPasswordToken: String
+    });
+
+    // Install passport plugin.
+    AccountSchema.plugin(passportMongo, {
+        usernameField: 'email', limitAttempts: true, lastLoginField: 'lastLogin',
+        usernameLowerCase: true
+    });
+
+    // Configure transformation to JSON.
+    AccountSchema.set('toJSON', {
+        transform: (doc, ret) => {
+            return {
+                _id: ret._id,
+                email: ret.email,
+                firstName: ret.firstName,
+                lastName: ret.lastName,
+                company: ret.company,
+                country: ret.country,
+                admin: ret.admin,
+                token: ret.token,
+                lastLogin: ret.lastLogin
+            };
+        }
+    });
+
+    result.errCodes = {
+        DUPLICATE_KEY_ERROR: 11000,
+        DUPLICATE_KEY_UPDATE_ERROR: 11001
+    };
+    // Define Account model.
+    result.Account = mongoose.model('Account', AccountSchema);
+
+    // Define Space model.
+    result.Space = mongoose.model('Space', new Schema({
+        name: String,
+        owner: {type: ObjectId, ref: 'Account'},
+        demo: {type: Boolean, default: false},
+        usedBy: [{
+            permission: {type: String, enum: ['VIEW', 'FULL']},
+            account: {type: ObjectId, ref: 'Account'}
+        }]
+    }));
+
+    // Define Domain model schema.
+    const DomainModelSchema = new Schema({
+        space: {type: ObjectId, ref: 'Space', index: true},
+        caches: [{type: ObjectId, ref: 'Cache'}],
+        queryMetadata: {type: String, enum: ['Annotations', 'Configuration']},
+        kind: {type: String, enum: ['query', 'store', 'both']},
+        databaseSchema: String,
+        databaseTable: String,
+        keyType: String,
+        valueType: {type: String},
+        keyFields: [{
+            databaseFieldName: String,
+            databaseFieldType: String,
+            javaFieldName: String,
+            javaFieldType: String
+        }],
+        valueFields: [{
+            databaseFieldName: String,
+            databaseFieldType: String,
+            javaFieldName: String,
+            javaFieldType: String
+        }],
+        fields: [{name: String, className: String}],
+        aliases: [{field: String, alias: String}],
+        indexes: [{
+            name: String,
+            indexType: {type: String, enum: ['SORTED', 'FULLTEXT', 'GEOSPATIAL']},
+            fields: [{name: String, direction: Boolean}]
+        }],
+        demo: Boolean
+    });
+
+    DomainModelSchema.index({valueType: 1, space: 1}, {unique: true});
+
+    // Define model of Domain models.
+    result.DomainModel = mongoose.model('DomainModel', DomainModelSchema);
+
+    // Define Cache schema.
+    const CacheSchema = new Schema({
+        space: {type: ObjectId, ref: 'Space', index: true},
+        name: {type: String},
+        clusters: [{type: ObjectId, ref: 'Cluster'}],
+        domains: [{type: ObjectId, ref: 'DomainModel'}],
+        cacheMode: {type: String, enum: ['PARTITIONED', 'REPLICATED', 'LOCAL']},
+        atomicityMode: {type: String, enum: ['ATOMIC', 'TRANSACTIONAL']},
+
+        nodeFilter: {
+            kind: {type: String, enum: ['Default', 'Exclude', 'IGFS', 'OnNodes', 'Custom']},
+            Exclude: {
+                nodeId: String
+            },
+            IGFS: {
+                igfs: {type: ObjectId, ref: 'Igfs'}
+            },
+            OnNodes: {
+                nodeIds: [String]
+            },
+            Custom: {
+                className: String
+            }
+        },
+
+        backups: Number,
+        memoryMode: {type: String, enum: ['ONHEAP_TIERED', 'OFFHEAP_TIERED', 'OFFHEAP_VALUES']},
+        offHeapMaxMemory: Number,
+        startSize: Number,
+        swapEnabled: Boolean,
+
+        evictionPolicy: {
+            kind: {type: String, enum: ['LRU', 'FIFO', 'SORTED']},
+            LRU: {
+                batchSize: Number,
+                maxMemorySize: Number,
+                maxSize: Number
+            },
+            FIFO: {
+                batchSize: Number,
+                maxMemorySize: Number,
+                maxSize: Number
+            },
+            SORTED: {
+                batchSize: Number,
+                maxMemorySize: Number,
+                maxSize: Number
+            }
+        },
+
+        rebalanceMode: {type: String, enum: ['SYNC', 'ASYNC', 'NONE']},
+        rebalanceBatchSize: Number,
+        rebalanceBatchesPrefetchCount: Number,
+        rebalanceOrder: Number,
+        rebalanceDelay: Number,
+        rebalanceTimeout: Number,
+        rebalanceThrottle: Number,
+
+        cacheStoreFactory: {
+            kind: {
+                type: String,
+                enum: ['CacheJdbcPojoStoreFactory', 'CacheJdbcBlobStoreFactory', 'CacheHibernateBlobStoreFactory']
+            },
+            CacheJdbcPojoStoreFactory: {
+                dataSourceBean: String,
+                dialect: {
+                    type: String,
+                    enum: ['Generic', 'Oracle', 'DB2', 'SQLServer', 'MySQL', 'PostgreSQL', 'H2']
+                }
+            },
+            CacheJdbcBlobStoreFactory: {
+                connectVia: {type: String, enum: ['URL', 'DataSource']},
+                connectionUrl: String,
+                user: String,
+                dataSourceBean: String,
+                dialect: {
+                    type: String,
+                    enum: ['Generic', 'Oracle', 'DB2', 'SQLServer', 'MySQL', 'PostgreSQL', 'H2']
+                },
+                initSchema: Boolean,
+                createTableQuery: String,
+                loadQuery: String,
+                insertQuery: String,
+                updateQuery: String,
+                deleteQuery: String
+            },
+            CacheHibernateBlobStoreFactory: {
+                hibernateProperties: [String]
+            }
+        },
+        storeKeepBinary: Boolean,
+        loadPreviousValue: Boolean,
+        readThrough: Boolean,
+        writeThrough: Boolean,
+
+        writeBehindEnabled: Boolean,
+        writeBehindBatchSize: Number,
+        writeBehindFlushSize: Number,
+        writeBehindFlushFrequency: Number,
+        writeBehindFlushThreadCount: Number,
+
+        invalidate: Boolean,
+        defaultLockTimeout: Number,
+        atomicWriteOrderMode: {type: String, enum: ['CLOCK', 'PRIMARY']},
+        writeSynchronizationMode: {type: String, enum: ['FULL_SYNC', 'FULL_ASYNC', 'PRIMARY_SYNC']},
+
+        sqlEscapeAll: Boolean,
+        sqlSchema: String,
+        sqlOnheapRowCacheSize: Number,
+        longQueryWarningTimeout: Number,
+        sqlFunctionClasses: [String],
+        snapshotableIndex: Boolean,
+        statisticsEnabled: Boolean,
+        managementEnabled: Boolean,
+        readFromBackup: Boolean,
+        copyOnRead: Boolean,
+        maxConcurrentAsyncOperations: Number,
+        nearCacheEnabled: Boolean,
+        nearConfiguration: {
+            nearStartSize: Number,
+            nearEvictionPolicy: {
+                kind: {type: String, enum: ['LRU', 'FIFO', 'SORTED']},
+                LRU: {
+                    batchSize: Number,
+                    maxMemorySize: Number,
+                    maxSize: Number
+                },
+                FIFO: {
+                    batchSize: Number,
+                    maxMemorySize: Number,
+                    maxSize: Number
+                },
+                SORTED: {
+                    batchSize: Number,
+                    maxMemorySize: Number,
+                    maxSize: Number
+                }
+            }
+        },
+        demo: Boolean
+    });
+
+    CacheSchema.index({name: 1, space: 1}, {unique: true});
+
+    // Define Cache model.
+    result.Cache = mongoose.model('Cache', CacheSchema);
+
+    const IgfsSchema = new Schema({
+        space: {type: ObjectId, ref: 'Space', index: true},
+        name: {type: String},
+        clusters: [{type: ObjectId, ref: 'Cluster'}],
+        affinnityGroupSize: Number,
+        blockSize: Number,
+        streamBufferSize: Number,
+        dataCacheName: String,
+        metaCacheName: String,
+        defaultMode: {type: String, enum: ['PRIMARY', 'PROXY', 'DUAL_SYNC', 'DUAL_ASYNC']},
+        dualModeMaxPendingPutsSize: Number,
+        dualModePutExecutorService: String,
+        dualModePutExecutorServiceShutdown: Boolean,
+        fragmentizerConcurrentFiles: Number,
+        fragmentizerEnabled: Boolean,
+        fragmentizerThrottlingBlockLength: Number,
+        fragmentizerThrottlingDelay: Number,
+        ipcEndpointConfiguration: {
+            type: {type: String, enum: ['SHMEM', 'TCP']},
+            host: String,
+            port: Number,
+            memorySize: Number,
+            tokenDirectoryPath: String,
+            threadCount: Number
+        },
+        ipcEndpointEnabled: Boolean,
+        maxSpaceSize: Number,
+        maximumTaskRangeLength: Number,
+        managementPort: Number,
+        pathModes: [{path: String, mode: {type: String, enum: ['PRIMARY', 'PROXY', 'DUAL_SYNC', 'DUAL_ASYNC']}}],
+        perNodeBatchSize: Number,
+        perNodeParallelBatchCount: Number,
+        prefetchBlocks: Number,
+        sequentialReadsBeforePrefetch: Number,
+        trashPurgeTimeout: Number,
+        secondaryFileSystemEnabled: Boolean,
+        secondaryFileSystem: {
+            uri: String,
+            cfgPath: String,
+            userName: String
+        },
+        colocateMetadata: Boolean,
+        relaxedConsistency: Boolean
+    });
+
+    IgfsSchema.index({name: 1, space: 1}, {unique: true});
+
+    // Define IGFS model.
+    result.Igfs = mongoose.model('Igfs', IgfsSchema);
+
+    // Define Cluster schema.
+    const ClusterSchema = new Schema({
+        space: {type: ObjectId, ref: 'Space', index: true},
+        name: {type: String},
+        localHost: String,
+        discovery: {
+            localAddress: String,
+            localPort: Number,
+            localPortRange: Number,
+            addressResolver: String,
+            socketTimeout: Number,
+            ackTimeout: Number,
+            maxAckTimeout: Number,
+            networkTimeout: Number,
+            joinTimeout: Number,
+            threadPriority: Number,
+            heartbeatFrequency: Number,
+            maxMissedHeartbeats: Number,
+            maxMissedClientHeartbeats: Number,
+            topHistorySize: Number,
+            listener: String,
+            dataExchange: String,
+            metricsProvider: String,
+            reconnectCount: Number,
+            statisticsPrintFrequency: Number,
+            ipFinderCleanFrequency: Number,
+            authenticator: String,
+            forceServerMode: Boolean,
+            clientReconnectDisabled: Boolean,
+            kind: {type: String, enum: ['Vm', 'Multicast', 'S3', 'Cloud', 'GoogleStorage', 'Jdbc', 'SharedFs', 'ZooKeeper']},
+            Vm: {
+                addresses: [String]
+            },
+            Multicast: {
+                multicastGroup: String,
+                multicastPort: Number,
+                responseWaitTime: Number,
+                addressRequestAttempts: Number,
+                localAddress: String,
+                addresses: [String]
+            },
+            S3: {
+                bucketName: String
+            },
+            Cloud: {
+                credential: String,
+                credentialPath: String,
+                identity: String,
+                provider: String,
+                regions: [String],
+                zones: [String]
+            },
+            GoogleStorage: {
+                projectName: String,
+                bucketName: String,
+                serviceAccountP12FilePath: String,
+                serviceAccountId: String,
+                addrReqAttempts: String
+            },
+            Jdbc: {
+                initSchema: Boolean,
+                dataSourceBean: String,
+                dialect: {
+                    type: String,
+                    enum: ['Generic', 'Oracle', 'DB2', 'SQLServer', 'MySQL', 'PostgreSQL', 'H2']
+                }
+            },
+            SharedFs: {
+                path: String
+            },
+            ZooKeeper: {
+                curator: String,
+                zkConnectionString: String,
+                retryPolicy: {
+                    kind: {type: String, enum: ['ExponentialBackoff', 'BoundedExponentialBackoff', 'UntilElapsed',
+                        'NTimes', 'OneTime', 'Forever', 'Custom']},
+                    ExponentialBackoff: {
+                        baseSleepTimeMs: Number,
+                        maxRetries: Number,
+                        maxSleepMs: Number
+                    },
+                    BoundedExponentialBackoff: {
+                        baseSleepTimeMs: Number,
+                        maxSleepTimeMs: Number,
+                        maxRetries: Number
+                    },
+                    UntilElapsed: {
+                        maxElapsedTimeMs: Number,
+                        sleepMsBetweenRetries: Number
+                    },
+                    NTimes: {
+                        n: Number,
+                        sleepMsBetweenRetries: Number
+                    },
+                    OneTime: {
+                        sleepMsBetweenRetry: Number
+                    },
+                    Forever: {
+                        retryIntervalMs: Number
+                    },
+                    Custom: {
+                        className: String
+                    }
+                },
+                basePath: String,
+                serviceName: String,
+                allowDuplicateRegistrations: Boolean
+            }
+        },
+        atomicConfiguration: {
+            backups: Number,
+            cacheMode: {type: String, enum: ['LOCAL', 'REPLICATED', 'PARTITIONED']},
+            atomicSequenceReserveSize: Number
+        },
+        binaryConfiguration: {
+            idMapper: String,
+            nameMapper: String,
+            serializer: String,
+            typeConfigurations: [{
+                typeName: String,
+                idMapper: String,
+                nameMapper: String,
+                serializer: String,
+                enum: Boolean
+            }],
+            compactFooter: Boolean
+        },
+        caches: [{type: ObjectId, ref: 'Cache'}],
+        clockSyncSamples: Number,
+        clockSyncFrequency: Number,
+        deploymentMode: {type: String, enum: ['PRIVATE', 'ISOLATED', 'SHARED', 'CONTINUOUS']},
+        discoveryStartupDelay: Number,
+        igfsThreadPoolSize: Number,
+        igfss: [{type: ObjectId, ref: 'Igfs'}],
+        includeEventTypes: [String],
+        managementThreadPoolSize: Number,
+        marshaller: {
+            kind: {type: String, enum: ['OptimizedMarshaller', 'JdkMarshaller']},
+            OptimizedMarshaller: {
+                poolSize: Number,
+                requireSerializable: Boolean
+            }
+        },
+        marshalLocalJobs: Boolean,
+        marshallerCacheKeepAliveTime: Number,
+        marshallerCacheThreadPoolSize: Number,
+        metricsExpireTime: Number,
+        metricsHistorySize: Number,
+        metricsLogFrequency: Number,
+        metricsUpdateFrequency: Number,
+        networkTimeout: Number,
+        networkSendRetryDelay: Number,
+        networkSendRetryCount: Number,
+        communication: {
+            listener: String,
+            localAddress: String,
+            localPort: Number,
+            localPortRange: Number,
+            sharedMemoryPort: Number,
+            directBuffer: Boolean,
+            directSendBuffer: Boolean,
+            idleConnectionTimeout: Number,
+            connectTimeout: Number,
+            maxConnectTimeout: Number,
+            reconnectCount: Number,
+            socketSendBuffer: Number,
+            socketReceiveBuffer: Number,
+            messageQueueLimit: Number,
+            slowClientQueueLimit: Number,
+            tcpNoDelay: Boolean,
+            ackSendThreshold: Number,
+            unacknowledgedMessagesBufferSize: Number,
+            socketWriteTimeout: Number,
+            selectorsCount: Number,
+            addressResolver: String
+        },
+        connector: {
+            enabled: Boolean,
+            jettyPath: String,
+            host: String,
+            port: Number,
+            portRange: Number,
+            idleTimeout: Number,
+            idleQueryCursorTimeout: Number,
+            idleQueryCursorCheckFrequency: Number,
+            receiveBufferSize: Number,
+            sendBufferSize: Number,
+            sendQueueLimit: Number,
+            directBuffer: Boolean,
+            noDelay: Boolean,
+            selectorCount: Number,
+            threadPoolSize: Number,
+            messageInterceptor: String,
+            secretKey: String,
+            sslEnabled: Boolean,
+            sslClientAuth: Boolean,
+            sslFactory: String
+        },
+        peerClassLoadingEnabled: Boolean,
+        peerClassLoadingLocalClassPathExclude: [String],
+        peerClassLoadingMissedResourcesCacheSize: Number,
+        peerClassLoadingThreadPoolSize: Number,
+        publicThreadPoolSize: Number,
+        swapSpaceSpi: {
+            kind: {type: String, enum: ['FileSwapSpaceSpi']},
+            FileSwapSpaceSpi: {
+                baseDirectory: String,
+                readStripesNumber: Number,
+                maximumSparsity: Number,
+                maxWriteQueueSize: Number,
+                writeBufferSize: Number
+            }
+        },
+        systemThreadPoolSize: Number,
+        timeServerPortBase: Number,
+        timeServerPortRange: Number,
+        transactionConfiguration: {
+            defaultTxConcurrency: {type: String, enum: ['OPTIMISTIC', 'PESSIMISTIC']},
+            defaultTxIsolation: {type: String, enum: ['READ_COMMITTED', 'REPEATABLE_READ', 'SERIALIZABLE']},
+            defaultTxTimeout: Number,
+            pessimisticTxLogLinger: Number,
+            pessimisticTxLogSize: Number,
+            txSerializableEnabled: Boolean,
+            txManagerFactory: String
+        },
+        sslEnabled: Boolean,
+        sslContextFactory: {
+            keyAlgorithm: String,
+            keyStoreFilePath: String,
+            keyStoreType: String,
+            protocol: String,
+            trustStoreFilePath: String,
+            trustStoreType: String,
+            trustManagers: [String]
+        },
+        rebalanceThreadPoolSize: Number,
+        attributes: [{name: String, value: String}],
+        collision: {
+            kind: {type: String, enum: ['Noop', 'PriorityQueue', 'FifoQueue', 'JobStealing', 'Custom']},
+            PriorityQueue: {
+                parallelJobsNumber: Number,
+                waitingJobsNumber: Number,
+                priorityAttributeKey: String,
+                jobPriorityAttributeKey: String,
+                defaultPriority: Number,
+                starvationIncrement: Number,
+                starvationPreventionEnabled: Boolean
+            },
+            FifoQueue: {
+                parallelJobsNumber: Number,
+                waitingJobsNumber: Number
+            },
+            JobStealing: {
+                activeJobsThreshold: Number,
+                waitJobsThreshold: Number,
+                messageExpireTime: Number,
+                maximumStealingAttempts: Number,
+                stealingEnabled: Boolean,
+                stealingAttributes: [{name: String, value: String}],
+                externalCollisionListener: String
+            },
+            Custom: {
+                class: String
+            }
+        },
+        failoverSpi: [{
+            kind: {type: String, enum: ['JobStealing', 'Never', 'Always', 'Custom']},
+            JobStealing: {
+                maximumFailoverAttempts: Number
+            },
+            Always: {
+                maximumFailoverAttempts: Number
+            },
+            Custom: {
+                class: String
+            }
+        }],
+        logger: {
+            kind: {type: 'String', enum: ['Log4j2', 'Null', 'Java', 'JCL', 'SLF4J', 'Log4j', 'Custom']},
+            Log4j2: {
+                level: {type: String, enum: ['OFF', 'FATAL', 'ERROR', 'WARN', 'INFO', 'DEBUG', 'TRACE', 'ALL']},
+                path: String
+            },
+            Log4j: {
+                mode: {type: String, enum: ['Default', 'Path']},
+                level: {type: String, enum: ['OFF', 'FATAL', 'ERROR', 'WARN', 'INFO', 'DEBUG', 'TRACE', 'ALL']},
+                path: String
+            },
+            Custom: {
+                class: String
+            }
+        },
+        cacheKeyConfiguration: [{
+            typeName: String,
+            affinityKeyFieldName: String
+        }]
+    });
+
+    ClusterSchema.index({name: 1, space: 1}, {unique: true});
+
+    // Define Cluster model.
+    result.Cluster = mongoose.model('Cluster', ClusterSchema);
+
+    // Define Notebook schema.
+    const NotebookSchema = new Schema({
+        space: {type: ObjectId, ref: 'Space', index: true},
+        name: String,
+        expandedParagraphs: [Number],
+        paragraphs: [{
+            name: String,
+            query: String,
+            editor: Boolean,
+            result: {type: String, enum: ['none', 'table', 'bar', 'pie', 'line', 'area']},
+            pageSize: Number,
+            timeLineSpan: String,
+            hideSystemColumns: Boolean,
+            cacheName: String,
+            chartsOptions: {barChart: {stacked: Boolean}, areaChart: {style: String}},
+            rate: {
+                value: Number,
+                unit: Number
+            }
+        }]
+    });
+
+    NotebookSchema.index({name: 1, space: 1}, {unique: true});
+
+    // Define Notebook model.
+    result.Notebook = mongoose.model('Notebook', NotebookSchema);
+
+    result.handleError = function(res, err) {
+        // TODO IGNITE-843 Send error to admin
+        res.status(err.code || 500).send(err.message);
+    };
+
+    // Registering the routes of all plugin modules
+    for (const name in pluginMongo) {
+        if (pluginMongo.hasOwnProperty(name))
+            pluginMongo[name].register(mongoose, result);
+    }
+
+    return result;
+};

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/backend/app/nconf.js
----------------------------------------------------------------------
diff --git a/modules/web-console/backend/app/nconf.js b/modules/web-console/backend/app/nconf.js
new file mode 100644
index 0000000..c585ac6
--- /dev/null
+++ b/modules/web-console/backend/app/nconf.js
@@ -0,0 +1,48 @@
+/*
+ * 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.
+ */
+
+'use strict';
+
+// Fire me up!
+
+/**
+ * Module with server-side configuration.
+ */
+module.exports = {
+    implements: 'nconf',
+    inject: ['require(nconf)', 'require(fs)']
+};
+
+module.exports.factory = function(nconf, fs) {
+    const default_config = './config/settings.json';
+    const file = process.env.SETTINGS || default_config;
+
+    nconf.env({separator: '_'});
+
+    try {
+        fs.accessSync(file, fs.F_OK);
+
+        nconf.file({file});
+    } catch (ignore) {
+        nconf.file({file: default_config});
+    }
+
+    if (process.env.CONFIG_PATH && fs.existsSync(process.env.CONFIG_PATH))
+        nconf.file({file: process.env.CONFIG_PATH});
+
+    return nconf;
+};

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/backend/app/routes.js
----------------------------------------------------------------------
diff --git a/modules/web-console/backend/app/routes.js b/modules/web-console/backend/app/routes.js
new file mode 100644
index 0000000..6961173
--- /dev/null
+++ b/modules/web-console/backend/app/routes.js
@@ -0,0 +1,64 @@
+/*
+ * 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.
+ */
+
+'use strict';
+
+// Fire me up!
+
+module.exports = {
+    implements: 'routes',
+    inject: ['routes/public', 'routes/admin', 'routes/profiles', 'routes/demo', 'routes/clusters', 'routes/domains',
+        'routes/caches', 'routes/igfss', 'routes/notebooks', 'routes/agents', 'routes/configurations']
+};
+
+module.exports.factory = function(publicRoute, adminRoute, profilesRoute, demoRoute,
+    clustersRoute, domainsRoute, cachesRoute, igfssRoute, notebooksRoute, agentsRoute, configurationsRoute) {
+    return {
+        register: (app) => {
+            const _mustAuthenticated = (req, res, next) => {
+                if (req.isAuthenticated())
+                    return next();
+
+                res.status(401).send('Access denied. You are not authorized to access this page.');
+            };
+
+            const _adminOnly = (req, res, next) => {
+                if (req.isAuthenticated() && req.user.admin)
+                    return next();
+
+                res.status(401).send('Access denied. You are not authorized to access this page.');
+            };
+
+            // Registering the standard routes
+            app.use('/', publicRoute);
+            app.use('/admin', _mustAuthenticated, _adminOnly, adminRoute);
+            app.use('/profile', _mustAuthenticated, profilesRoute);
+            app.use('/demo', _mustAuthenticated, demoRoute);
+
+            app.all('/configuration/*', _mustAuthenticated);
+
+            app.use('/configuration', configurationsRoute);
+            app.use('/configuration/clusters', clustersRoute);
+            app.use('/configuration/domains', domainsRoute);
+            app.use('/configuration/caches', cachesRoute);
+            app.use('/configuration/igfs', igfssRoute);
+
+            app.use('/notebooks', _mustAuthenticated, notebooksRoute);
+            app.use('/agent', _mustAuthenticated, agentsRoute);
+        }
+    };
+};


[21/52] ignite git commit: Web Console beta-3.

Posted by ak...@apache.org.
http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/src/main/js/app/directives/information/information.scss
----------------------------------------------------------------------
diff --git a/modules/web-console/src/main/js/app/directives/information/information.scss b/modules/web-console/src/main/js/app/directives/information/information.scss
deleted file mode 100644
index 39f3c05..0000000
--- a/modules/web-console/src/main/js/app/directives/information/information.scss
+++ /dev/null
@@ -1,56 +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-block-information: #fcfcfc;
-$ignite-block-information-border: #aab8c6;
-$ignite-block-information-icon: #4a6785;
-
-.block-information {
-    position: relative;
-
-    background: $ignite-block-information;
-
-    border-radius: 5px;
-    border: 1px solid $ignite-block-information-border;
-
-    margin: 20px 0;
-    padding: 10px 10px 0 30px;
-
-    > h3 {
-        font-weight: bold;
-        margin-bottom: 10px;
-    }
-
-    > .icon {
-        cursor: default;
-
-        color: $ignite-block-information-icon;
-
-        position: absolute;
-        top: 12px;
-        left: 10px;
-
-        font-size: 16px;
-
-        vertical-align: text-bottom
-    }
-
-    ul {
-        padding-left: 20px;
-    }
-}
-

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/src/main/js/app/directives/match.directive.js
----------------------------------------------------------------------
diff --git a/modules/web-console/src/main/js/app/directives/match.directive.js b/modules/web-console/src/main/js/app/directives/match.directive.js
deleted file mode 100644
index 3a45f6d..0000000
--- a/modules/web-console/src/main/js/app/directives/match.directive.js
+++ /dev/null
@@ -1,27 +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.
- */
-
-// Directive to enable validation to match specified value.
-export default ['igniteMatch', ['$parse', ($parse) => {
-    return {
-        require: 'ngModel',
-        link(scope, elem, attrs, ctrl) {
-            scope.$watch(() => $parse(attrs.igniteMatch)(scope) === ctrl.$modelValue,
-                (currentValue) => ctrl.$setValidity('mismatch', currentValue));
-        }
-    };
-}]];

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/src/main/js/app/directives/on-click-focus.directive.js
----------------------------------------------------------------------
diff --git a/modules/web-console/src/main/js/app/directives/on-click-focus.directive.js b/modules/web-console/src/main/js/app/directives/on-click-focus.directive.js
deleted file mode 100644
index 5c9ee88..0000000
--- a/modules/web-console/src/main/js/app/directives/on-click-focus.directive.js
+++ /dev/null
@@ -1,26 +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.
- */
-
-// Directive to describe element that should be focused on click.
-export default ['igniteOnClickFocus', ['IgniteFocus', (Focus) => {
-    return function(scope, elem, attrs) {
-        elem.on('click', () => Focus.move(attrs.igniteOnClickFocus));
-
-        // Removes bound events in the element itself when the scope is destroyed
-        scope.$on('$destroy', () => elem.off('click'));
-    };
-}]];

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/src/main/js/app/directives/on-enter-focus-move.directive.js
----------------------------------------------------------------------
diff --git a/modules/web-console/src/main/js/app/directives/on-enter-focus-move.directive.js b/modules/web-console/src/main/js/app/directives/on-enter-focus-move.directive.js
deleted file mode 100644
index 2dd2884..0000000
--- a/modules/web-console/src/main/js/app/directives/on-enter-focus-move.directive.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.
- */
-
-// Directive to move focus to specified element on ENTER key.
-export default ['igniteOnEnterFocusMove', ['IgniteFocus', (Focus) => {
-    return function(scope, elem, attrs) {
-        elem.on('keydown keypress', (event) => {
-            if (event.which === 13) {
-                event.preventDefault();
-
-                Focus.move(attrs.igniteOnEnterFocusMove);
-            }
-        });
-    };
-}]];

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/src/main/js/app/directives/on-enter.directive.js
----------------------------------------------------------------------
diff --git a/modules/web-console/src/main/js/app/directives/on-enter.directive.js b/modules/web-console/src/main/js/app/directives/on-enter.directive.js
deleted file mode 100644
index 459220e..0000000
--- a/modules/web-console/src/main/js/app/directives/on-enter.directive.js
+++ /dev/null
@@ -1,32 +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.
- */
-
-// Directive to bind ENTER key press with some user action.
-export default ['igniteOnEnter', ['$timeout', ($timeout) => {
-    return function(scope, elem, attrs) {
-        elem.on('keydown keypress', (event) => {
-            if (event.which === 13) {
-                scope.$apply(() => $timeout(() => scope.$eval(attrs.igniteOnEnter)));
-
-                event.preventDefault();
-            }
-        });
-
-        // Removes bound events in the element itself when the scope is destroyed.
-        scope.$on('$destroy', () => elem.off('keydown keypress'));
-    };
-}]];

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/src/main/js/app/directives/on-escape.directive.js
----------------------------------------------------------------------
diff --git a/modules/web-console/src/main/js/app/directives/on-escape.directive.js b/modules/web-console/src/main/js/app/directives/on-escape.directive.js
deleted file mode 100644
index aa1accd..0000000
--- a/modules/web-console/src/main/js/app/directives/on-escape.directive.js
+++ /dev/null
@@ -1,32 +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.
- */
-
-// Directive to bind ESC key press with some user action.
-export default ['igniteOnEscape', ['$timeout', ($timeout) => {
-    return function(scope, elem, attrs) {
-        elem.on('keydown keypress', (event) => {
-            if (event.which === 27) {
-                scope.$apply(() => $timeout(() => scope.$eval(attrs.igniteOnEscape)));
-
-                event.preventDefault();
-            }
-        });
-
-        // Removes bound events in the element itself when the scope is destroyed.
-        scope.$on('$destroy', () => elem.off('keydown keypress'));
-    };
-}]];

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/src/main/js/app/directives/ui-ace-docker/ui-ace-docker.controller.js
----------------------------------------------------------------------
diff --git a/modules/web-console/src/main/js/app/directives/ui-ace-docker/ui-ace-docker.controller.js b/modules/web-console/src/main/js/app/directives/ui-ace-docker/ui-ace-docker.controller.js
deleted file mode 100644
index 32feaf3..0000000
--- a/modules/web-console/src/main/js/app/directives/ui-ace-docker/ui-ace-docker.controller.js
+++ /dev/null
@@ -1,33 +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 ['$scope', 'GeneratorDocker', function($scope, docker) {
-    const ctrl = this;
-
-    // Watchers definition.
-    const clusterWatcher = () => {
-        delete ctrl.data;
-
-        if (!$scope.cluster)
-            return;
-
-        ctrl.data = docker.generate($scope.cluster, 'latest');
-    };
-
-    // Setup watchers.
-    $scope.$watch('cluster', clusterWatcher);
-}];

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/src/main/js/app/directives/ui-ace-docker/ui-ace-docker.directive.js
----------------------------------------------------------------------
diff --git a/modules/web-console/src/main/js/app/directives/ui-ace-docker/ui-ace-docker.directive.js b/modules/web-console/src/main/js/app/directives/ui-ace-docker/ui-ace-docker.directive.js
deleted file mode 100644
index 08e4f76..0000000
--- a/modules/web-console/src/main/js/app/directives/ui-ace-docker/ui-ace-docker.directive.js
+++ /dev/null
@@ -1,46 +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 templateUrl from './ui-ace-docker.jade';
-import controller from './ui-ace-docker.controller';
-
-export default ['igniteUiAceDocker', [() => {
-    const link = ($scope, $el, $attrs, [igniteUiAceTabs]) => {
-        if (igniteUiAceTabs.onLoad)
-            $scope.onLoad = igniteUiAceTabs.onLoad;
-
-        if (igniteUiAceTabs.onChange)
-            $scope.onChange = igniteUiAceTabs.onChange;
-    };
-
-    return {
-        restrict: 'E',
-        scope: {
-            cluster: '=',
-            data: '=ngModel'
-        },
-        bindToController: {
-            cluster: '=',
-            data: '=ngModel'
-        },
-        link,
-        templateUrl,
-        controller,
-        controllerAs: 'ctrl',
-        require: ['?^igniteUiAceTabs']
-    };
-}]];

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/src/main/js/app/directives/ui-ace-docker/ui-ace-docker.jade
----------------------------------------------------------------------
diff --git a/modules/web-console/src/main/js/app/directives/ui-ace-docker/ui-ace-docker.jade b/modules/web-console/src/main/js/app/directives/ui-ace-docker/ui-ace-docker.jade
deleted file mode 100644
index 3b0e7b8..0000000
--- a/modules/web-console/src/main/js/app/directives/ui-ace-docker/ui-ace-docker.jade
+++ /dev/null
@@ -1,31 +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.
-
-mixin hard-link(ref, txt)
-    a(style='color:#ec1c24' href=ref target='_blank') #{txt}
-
-.panel-details-noborder
-    .details-row
-        p
-            +hard-link('https://docs.docker.com/reference/builder', 'Docker')
-            | &nbsp;file is a text file with instructions to create Docker image.<br/>
-            | To build image you have to store following Docker file with your Ignite XML configuration to the same directory.<br>
-            | Also you could use predefined&nbsp;
-            +hard-link('https://ignite.apache.org/download.html#docker', 'Apache Ignite docker image')
-            | . For more information about using Ignite with Docker please read&nbsp;
-            +hard-link('http://apacheignite.readme.io/docs/docker-deployment', 'documentation')
-            |.
-    .details-row(ng-if='ctrl.data' ignite-ace='{onLoad: onLoad, mode: "dockerfile"}' ng-model='ctrl.data')

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/src/main/js/app/directives/ui-ace-java/ui-ace-java.controller.js
----------------------------------------------------------------------
diff --git a/modules/web-console/src/main/js/app/directives/ui-ace-java/ui-ace-java.controller.js b/modules/web-console/src/main/js/app/directives/ui-ace-java/ui-ace-java.controller.js
deleted file mode 100644
index f869e65..0000000
--- a/modules/web-console/src/main/js/app/directives/ui-ace-java/ui-ace-java.controller.js
+++ /dev/null
@@ -1,32 +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.
- */
-
-const SERVER_CFG = 'ServerConfigurationFactory';
-const CLIENT_CFG = 'ClientConfigurationFactory';
-
-export default ['$scope', 'GeneratorJava', function($scope, generator) {
-    const ctrl = this;
-
-    delete ctrl.data;
-
-    // Set default generator
-    ctrl.generator = (cluster) => {
-        const type = $scope.cfg ? CLIENT_CFG : SERVER_CFG;
-
-        return generator.cluster(cluster, 'config', type, $scope.cfg);
-    };
-}];

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/src/main/js/app/directives/ui-ace-java/ui-ace-java.directive.js
----------------------------------------------------------------------
diff --git a/modules/web-console/src/main/js/app/directives/ui-ace-java/ui-ace-java.directive.js b/modules/web-console/src/main/js/app/directives/ui-ace-java/ui-ace-java.directive.js
deleted file mode 100644
index 17d3a00..0000000
--- a/modules/web-console/src/main/js/app/directives/ui-ace-java/ui-ace-java.directive.js
+++ /dev/null
@@ -1,133 +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 templateUrl from './ui-ace-java.jade';
-import controller from './ui-ace-java.controller';
-
-export default ['igniteUiAceJava', ['GeneratorJava', (generator) => {
-    const link = (scope, $el, attrs, [ctrl, igniteUiAceTabs, formCtrl, ngModelCtrl]) => {
-        if (formCtrl && ngModelCtrl)
-            formCtrl.$removeControl(ngModelCtrl);
-
-        if (igniteUiAceTabs && igniteUiAceTabs.onLoad) {
-            scope.onLoad = (editor) => {
-                igniteUiAceTabs.onLoad(editor);
-
-                scope.$watch('master', () => editor.attractAttention = false);
-            };
-        }
-
-        if (igniteUiAceTabs && igniteUiAceTabs.onChange)
-            scope.onChange = igniteUiAceTabs.onChange;
-
-        const render = (data) => {
-            delete ctrl.data;
-
-            if (!data)
-                return;
-
-            return ctrl.generator(scope.master);
-        };
-
-        // Setup generator.
-        if (scope.generator) {
-            const method = scope.generator;
-
-            switch (method) {
-                case 'clusterCaches':
-                    ctrl.generator = (cluster) => {
-                        const caches = _.reduce(scope.detail, (acc, cache) => {
-                            if (_.includes(cluster.caches, cache.value))
-                                acc.push(cache.cache);
-
-                            return acc;
-                        }, []);
-
-                        return generator.clusterCaches(caches, null, true, generator.clusterGeneral(cluster)).asString();
-                    };
-
-                    break;
-
-                case 'igfss':
-                    ctrl.generator = (cluster) => {
-                        const igfss = _.reduce(scope.detail, (acc, igfs) => {
-                            if (_.includes(cluster.igfss, igfs.value))
-                                acc.push(igfs.igfs);
-
-                            return acc;
-                        }, []);
-
-                        return generator.igfss(igfss, 'cfg').asString();
-                    };
-
-                    break;
-
-                case 'cacheStore':
-                    ctrl.generator = (cache) => {
-                        const domains = _.reduce(scope.detail, (acc, domain) => {
-                            if (_.includes(cache.domains, domain.value))
-                                acc.push(domain.meta);
-
-                            return acc;
-                        }, []);
-
-                        return generator.cacheStore(cache, domains).asString();
-                    };
-
-                    break;
-
-                default:
-                    ctrl.generator = (data) => generator[method](data).asString();
-            }
-        }
-
-        if (!_.isUndefined(attrs.clusterCfg)) {
-            scope.$watch('cfg', (cfg) => {
-                if (!_.isUndefined(cfg))
-                    return;
-
-                scope.cfg = {};
-            });
-
-            scope.$watch('cfg', (data) => ctrl.data = render(data), true);
-        }
-
-        const noDeepWatch = !(typeof attrs.noDeepWatch !== 'undefined');
-
-        // Setup watchers.
-        scope.$watch('master', (data) => ctrl.data = render(data), noDeepWatch);
-    };
-
-    return {
-        priority: 1,
-        restrict: 'E',
-        scope: {
-            master: '=',
-            detail: '=',
-            generator: '@',
-            cfg: '=?clusterCfg'
-        },
-        bindToController: {
-            data: '=?ngModel'
-        },
-        link,
-        templateUrl,
-        controller,
-        controllerAs: 'ctrl',
-        require: ['igniteUiAceJava', '?^igniteUiAceTabs', '?^form', '?ngModel']
-    };
-}]];

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/src/main/js/app/directives/ui-ace-java/ui-ace-java.jade
----------------------------------------------------------------------
diff --git a/modules/web-console/src/main/js/app/directives/ui-ace-java/ui-ace-java.jade b/modules/web-console/src/main/js/app/directives/ui-ace-java/ui-ace-java.jade
deleted file mode 100644
index 5acffb8..0000000
--- a/modules/web-console/src/main/js/app/directives/ui-ace-java/ui-ace-java.jade
+++ /dev/null
@@ -1,22 +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.
-
-div(ng-if='ctrl.data' 
-    ignite-ace='{onLoad: onLoad, \
-             onChange: onChange, \
-             renderOptions: renderOptions, \
-             mode: "java"}' 
-    ng-model='ctrl.data')

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/src/main/js/app/directives/ui-ace-pojos/ui-ace-pojos.controller.js
----------------------------------------------------------------------
diff --git a/modules/web-console/src/main/js/app/directives/ui-ace-pojos/ui-ace-pojos.controller.js b/modules/web-console/src/main/js/app/directives/ui-ace-pojos/ui-ace-pojos.controller.js
deleted file mode 100644
index bc185b3..0000000
--- a/modules/web-console/src/main/js/app/directives/ui-ace-pojos/ui-ace-pojos.controller.js
+++ /dev/null
@@ -1,95 +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 ['$scope', 'JavaTypes', 'GeneratorJava', function($scope, JavaTypes, generator) {
-    const ctrl = this;
-
-    // Watchers definition.
-    // Watcher clean instance data if instance to cluster caches was change
-    const cleanPojos = () => {
-        delete ctrl.class;
-        delete ctrl.pojos;
-        delete ctrl.classes;
-    };
-
-    // Watcher update pojos when changes caches and checkers useConstructor and includeKeyFields
-    const updatePojos = () => {
-        delete ctrl.pojos;
-
-        if (!ctrl.cluster || !ctrl.cluster.caches)
-            return;
-
-        ctrl.pojos = generator.pojos(ctrl.cluster.caches, ctrl.useConstructor, ctrl.includeKeyFields);
-    };
-
-    // Watcher update classes after
-    const updateClasses = (value) => {
-        delete ctrl.classes;
-
-        if (!value)
-            return;
-
-        const classes = ctrl.classes = [];
-
-        _.forEach(ctrl.pojos, (pojo) => {
-            if (pojo.keyType && JavaTypes.nonBuiltInClass(pojo.keyType))
-                classes.push(pojo.keyType);
-
-            classes.push(pojo.valueType);
-        });
-    };
-
-    // Update pojos class.
-    const updateClass = (value) => {
-        if (!value || !ctrl.pojos.length)
-            return;
-
-        const keyType = ctrl.pojos[0].keyType;
-
-        ctrl.class = ctrl.class || (JavaTypes.nonBuiltInClass(keyType) ? keyType : null) || ctrl.pojos[0].valueType;
-    };
-
-    // Update pojos data.
-    const updatePojosData = (value) => {
-        if (!value)
-            return;
-
-        _.forEach(ctrl.pojos, (pojo) => {
-            if (pojo.keyType === ctrl.class) {
-                ctrl.data = pojo.keyClass;
-
-                return false;
-            }
-
-            if (pojo.valueType === ctrl.class) {
-                ctrl.data = pojo.valueClass;
-
-                return false;
-            }
-        });
-    };
-
-    // Setup watchers. Watchers order is important.
-    $scope.$watch('ctrl.cluster.caches', cleanPojos);
-    $scope.$watch('ctrl.cluster.caches', updatePojos);
-    $scope.$watch('ctrl.cluster.caches', updateClasses);
-    $scope.$watch('ctrl.useConstructor', updatePojos);
-    $scope.$watch('ctrl.includeKeyFields', updatePojos);
-    $scope.$watch('ctrl.pojos', updateClass);
-    $scope.$watch('ctrl.pojos', updatePojosData);
-    $scope.$watch('ctrl.class', updatePojosData);
-}];

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/src/main/js/app/directives/ui-ace-pojos/ui-ace-pojos.directive.js
----------------------------------------------------------------------
diff --git a/modules/web-console/src/main/js/app/directives/ui-ace-pojos/ui-ace-pojos.directive.js b/modules/web-console/src/main/js/app/directives/ui-ace-pojos/ui-ace-pojos.directive.js
deleted file mode 100644
index 7c224b7..0000000
--- a/modules/web-console/src/main/js/app/directives/ui-ace-pojos/ui-ace-pojos.directive.js
+++ /dev/null
@@ -1,46 +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 templateUrl from './ui-ace-pojos.jade';
-import controller from './ui-ace-pojos.controller';
-
-export default ['igniteUiAcePojos', [() => {
-    const link = ($scope, $el, $attrs, [igniteUiAceTabs]) => {
-        if (igniteUiAceTabs.onLoad)
-            $scope.onLoad = igniteUiAceTabs.onLoad;
-
-        if (igniteUiAceTabs.onChange)
-            $scope.onChange = igniteUiAceTabs.onChange;
-    };
-
-    return {
-        restrict: 'E',
-        scope: {
-            cluster: '=',
-            pojos: '=ngModel'
-        },
-        bindToController: {
-            cluster: '=',
-            pojos: '=ngModel'
-        },
-        link,
-        templateUrl,
-        controller,
-        controllerAs: 'ctrl',
-        require: ['?^igniteUiAceTabs']
-    };
-}]];

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/src/main/js/app/directives/ui-ace-pojos/ui-ace-pojos.jade
----------------------------------------------------------------------
diff --git a/modules/web-console/src/main/js/app/directives/ui-ace-pojos/ui-ace-pojos.jade b/modules/web-console/src/main/js/app/directives/ui-ace-pojos/ui-ace-pojos.jade
deleted file mode 100644
index ed1432b..0000000
--- a/modules/web-console/src/main/js/app/directives/ui-ace-pojos/ui-ace-pojos.jade
+++ /dev/null
@@ -1,40 +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.
-
-mixin check-tooltip(message)
-    i.tipLabel.fa.fa-question-circle(bs-tooltip='"#{message}"')
-
-.panel-details-noborder
-    .details-row
-        .col-xs-2.col-sm-2.col-md-2
-            label POJO class:
-        .col-xs-10.col-sm-10.col-md-10.summary-pojo-list
-            button.select-toggle.form-control(ng-model='ctrl.class' bs-select bs-options='item for item in ctrl.classes' data-container='')
-    .details-row.checkbox
-        .col-xs-2.col-sm-2.col-md-2
-        .col-xs-10.col-sm-10.col-md-10
-            label
-                input(type='checkbox' ng-model='ctrl.useConstructor')
-                | Generate constructors
-            +check-tooltip("Generate empty and full constructors in POJO classes")
-    .details-row.checkbox
-        .col-xs-2.col-sm-2.col-md-2
-        .col-xs-10.col-sm-10.col-md-10
-            label
-                input(type='checkbox' ng-model='ctrl.includeKeyFields')
-                | Include key fields
-            +check-tooltip("Generate key fields in POJO value class")
-    .details-row(ng-if='ctrl.data' ignite-ace='{onLoad: onLoad, mode: "java"}' ng-model='ctrl.data')

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/src/main/js/app/directives/ui-ace-pom/ui-ace-pom.controller.js
----------------------------------------------------------------------
diff --git a/modules/web-console/src/main/js/app/directives/ui-ace-pom/ui-ace-pom.controller.js b/modules/web-console/src/main/js/app/directives/ui-ace-pom/ui-ace-pom.controller.js
deleted file mode 100644
index ec880bd..0000000
--- a/modules/web-console/src/main/js/app/directives/ui-ace-pom/ui-ace-pom.controller.js
+++ /dev/null
@@ -1,33 +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 ['$scope', 'GeneratorPom', 'IgniteVersion', function($scope, pom, IgniteVersion) {
-    const ctrl = this;
-
-    // Watchers definition.
-    const clusterWatcher = (value) => {
-        delete ctrl.data;
-
-        if (!value)
-            return;
-
-        ctrl.data = pom.generate($scope.cluster, IgniteVersion.version).asString();
-    };
-
-    // Setup watchers.
-    $scope.$watch('cluster', clusterWatcher);
-}];

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/src/main/js/app/directives/ui-ace-pom/ui-ace-pom.directive.js
----------------------------------------------------------------------
diff --git a/modules/web-console/src/main/js/app/directives/ui-ace-pom/ui-ace-pom.directive.js b/modules/web-console/src/main/js/app/directives/ui-ace-pom/ui-ace-pom.directive.js
deleted file mode 100644
index 2a7a878..0000000
--- a/modules/web-console/src/main/js/app/directives/ui-ace-pom/ui-ace-pom.directive.js
+++ /dev/null
@@ -1,41 +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 templateUrl from './ui-ace-pom.jade';
-import controller from './ui-ace-pom.controller';
-
-export default ['igniteUiAcePom', [() => {
-    const link = ($scope, $el, $attrs, [igniteUiAceTabs]) => {
-        if (igniteUiAceTabs.onLoad)
-            $scope.onLoad = igniteUiAceTabs.onLoad;
-
-        if (igniteUiAceTabs.onChange)
-            $scope.onChange = igniteUiAceTabs.onChange;
-    };
-
-    return {
-        restrict: 'E',
-        scope: {
-            cluster: '='
-        },
-        link,
-        templateUrl,
-        controller,
-        controllerAs: 'ctrl',
-        require: ['?^igniteUiAceTabs']
-    };
-}]];

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/src/main/js/app/directives/ui-ace-pom/ui-ace-pom.jade
----------------------------------------------------------------------
diff --git a/modules/web-console/src/main/js/app/directives/ui-ace-pom/ui-ace-pom.jade b/modules/web-console/src/main/js/app/directives/ui-ace-pom/ui-ace-pom.jade
deleted file mode 100644
index b973a74..0000000
--- a/modules/web-console/src/main/js/app/directives/ui-ace-pom/ui-ace-pom.jade
+++ /dev/null
@@ -1,17 +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.
-
-div(ng-if='ctrl.data' ignite-ace='{onLoad: onLoad, mode: "xml"}' ng-model='ctrl.data')

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/src/main/js/app/directives/ui-ace-tabs.directive.js
----------------------------------------------------------------------
diff --git a/modules/web-console/src/main/js/app/directives/ui-ace-tabs.directive.js b/modules/web-console/src/main/js/app/directives/ui-ace-tabs.directive.js
deleted file mode 100644
index a9649c8..0000000
--- a/modules/web-console/src/main/js/app/directives/ui-ace-tabs.directive.js
+++ /dev/null
@@ -1,23 +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 ['igniteUiAceTabs', [() => {
-    return {
-        restrict: 'AE',
-        controller: _.noop
-    };
-}]];

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/src/main/js/app/directives/ui-ace-xml/ui-ace-xml.controller.js
----------------------------------------------------------------------
diff --git a/modules/web-console/src/main/js/app/directives/ui-ace-xml/ui-ace-xml.controller.js b/modules/web-console/src/main/js/app/directives/ui-ace-xml/ui-ace-xml.controller.js
deleted file mode 100644
index 3233757..0000000
--- a/modules/web-console/src/main/js/app/directives/ui-ace-xml/ui-ace-xml.controller.js
+++ /dev/null
@@ -1,27 +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 ['$scope', 'GeneratorXml', function($scope, generator) {
-    const ctrl = this;
-
-    delete ctrl.data;
-
-    // Set default generator
-    ctrl.generator = (cluster) => {
-        return generator.cluster(cluster, $scope.cfg);
-    };
-}];

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/src/main/js/app/directives/ui-ace-xml/ui-ace-xml.directive.js
----------------------------------------------------------------------
diff --git a/modules/web-console/src/main/js/app/directives/ui-ace-xml/ui-ace-xml.directive.js b/modules/web-console/src/main/js/app/directives/ui-ace-xml/ui-ace-xml.directive.js
deleted file mode 100644
index 3bae4de..0000000
--- a/modules/web-console/src/main/js/app/directives/ui-ace-xml/ui-ace-xml.directive.js
+++ /dev/null
@@ -1,133 +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 templateUrl from './ui-ace-xml.jade';
-import controller from './ui-ace-xml.controller';
-
-export default ['igniteUiAceXml', ['GeneratorXml', (generator) => {
-    const link = (scope, $el, attrs, [ctrl, igniteUiAceTabs, formCtrl, ngModelCtrl]) => {
-        if (formCtrl && ngModelCtrl)
-            formCtrl.$removeControl(ngModelCtrl);
-
-        if (igniteUiAceTabs && igniteUiAceTabs.onLoad) {
-            scope.onLoad = (editor) => {
-                igniteUiAceTabs.onLoad(editor);
-
-                scope.$watch('master', () => editor.attractAttention = false);
-            };
-        }
-
-        if (igniteUiAceTabs && igniteUiAceTabs.onChange)
-            scope.onChange = igniteUiAceTabs.onChange;
-
-        const render = (data) => {
-            delete ctrl.data;
-
-            if (!data)
-                return;
-
-            return ctrl.generator(scope.master);
-        };
-
-        // Setup generator.
-        if (scope.generator) {
-            const method = scope.generator;
-
-            switch (method) {
-                case 'clusterCaches':
-                    ctrl.generator = (cluster) => {
-                        const caches = _.reduce(scope.detail, (acc, cache) => {
-                            if (_.includes(cluster.caches, cache.value))
-                                acc.push(cache.cache);
-
-                            return acc;
-                        }, []);
-
-                        return generator.clusterCaches(caches, null, true, generator.clusterGeneral(cluster)).asString();
-                    };
-
-                    break;
-
-                case 'igfss':
-                    ctrl.generator = (cluster) => {
-                        const igfss = _.reduce(scope.detail, (acc, igfs) => {
-                            if (_.includes(cluster.igfss, igfs.value))
-                                acc.push(igfs.igfs);
-
-                            return acc;
-                        }, []);
-
-                        return generator.igfss(igfss).asString();
-                    };
-
-                    break;
-
-                case 'cacheStore':
-                    ctrl.generator = (cache) => {
-                        const domains = _.reduce(scope.detail, (acc, domain) => {
-                            if (_.includes(cache.domains, domain.value))
-                                acc.push(domain.meta);
-
-                            return acc;
-                        }, []);
-
-                        return generator.cacheStore(cache, domains).asString();
-                    };
-
-                    break;
-
-                default:
-                    ctrl.generator = (data) => generator[method](data).asString();
-            }
-        }
-
-        if (!_.isUndefined(attrs.clusterCfg)) {
-            scope.$watch('cfg', (cfg) => {
-                if (!_.isUndefined(cfg))
-                    return;
-
-                scope.cfg = {};
-            });
-
-            scope.$watch('cfg', (data) => ctrl.data = render(data), true);
-        }
-
-        const noDeepWatch = !(typeof attrs.noDeepWatch !== 'undefined');
-
-        // Setup watchers.
-        scope.$watch('master', (data) => ctrl.data = render(data), noDeepWatch);
-    };
-
-    return {
-        priority: 1,
-        restrict: 'E',
-        scope: {
-            master: '=',
-            detail: '=',
-            generator: '@',
-            cfg: '=?clusterCfg'
-        },
-        bindToController: {
-            data: '=?ngModel'
-        },
-        link,
-        templateUrl,
-        controller,
-        controllerAs: 'ctrl',
-        require: ['igniteUiAceXml', '?^igniteUiAceTabs', '?^form', '?ngModel']
-    };
-}]];

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/src/main/js/app/directives/ui-ace-xml/ui-ace-xml.jade
----------------------------------------------------------------------
diff --git a/modules/web-console/src/main/js/app/directives/ui-ace-xml/ui-ace-xml.jade b/modules/web-console/src/main/js/app/directives/ui-ace-xml/ui-ace-xml.jade
deleted file mode 100644
index 0dd627a..0000000
--- a/modules/web-console/src/main/js/app/directives/ui-ace-xml/ui-ace-xml.jade
+++ /dev/null
@@ -1,17 +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.
-
-div(ng-if='ctrl.data' ignite-ace='{onLoad: onLoad, onChange: onChange, mode: "xml"}' ng-model='ctrl.data')

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/src/main/js/app/filters/byName.filter.js
----------------------------------------------------------------------
diff --git a/modules/web-console/src/main/js/app/filters/byName.filter.js b/modules/web-console/src/main/js/app/filters/byName.filter.js
deleted file mode 100644
index 3b0746f..0000000
--- a/modules/web-console/src/main/js/app/filters/byName.filter.js
+++ /dev/null
@@ -1,23 +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 ['byName', [() => (arr, search) => {
-    if (!(arr && arr.length) || !search)
-        return arr;
-
-    return _.filter(arr, ({ name }) => name.indexOf(search) >= 0);
-}]];

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/src/main/js/app/filters/domainsValidation.filter.js
----------------------------------------------------------------------
diff --git a/modules/web-console/src/main/js/app/filters/domainsValidation.filter.js b/modules/web-console/src/main/js/app/filters/domainsValidation.filter.js
deleted file mode 100644
index 1a38392..0000000
--- a/modules/web-console/src/main/js/app/filters/domainsValidation.filter.js
+++ /dev/null
@@ -1,33 +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.
- */
-
-// Filter domain models with key fields configuration.
-export default ['domainsValidation', ['IgniteLegacyUtils', (LegacyUtils) => (domains, valid, invalid) => {
-    if (valid && invalid)
-        return domains;
-
-    const out = [];
-
-    _.forEach(domains, function(domain) {
-        const _valid = !LegacyUtils.domainForStoreConfigured(domain) || LegacyUtils.isJavaBuiltInClass(domain.keyType) || !_.isEmpty(domain.keyFields);
-
-        if (valid && _valid || invalid && !_valid)
-            out.push(domain);
-    });
-
-    return out;
-}]];

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/src/main/js/app/filters/hasPojo.filter.js
----------------------------------------------------------------------
diff --git a/modules/web-console/src/main/js/app/filters/hasPojo.filter.js b/modules/web-console/src/main/js/app/filters/hasPojo.filter.js
deleted file mode 100644
index a179423..0000000
--- a/modules/web-console/src/main/js/app/filters/hasPojo.filter.js
+++ /dev/null
@@ -1,18 +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 ['hasPojo', [() => ({caches} = []) => _.find(caches, (cache) => cache.domains && cache.domains.length)]];

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/src/main/js/app/helpers/jade/mixins.jade
----------------------------------------------------------------------
diff --git a/modules/web-console/src/main/js/app/helpers/jade/mixins.jade b/modules/web-console/src/main/js/app/helpers/jade/mixins.jade
deleted file mode 100644
index 08ebe87..0000000
--- a/modules/web-console/src/main/js/app/helpers/jade/mixins.jade
+++ /dev/null
@@ -1,588 +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.
-
-//- Mixin for advanced options toggle.
-mixin advanced-options-toggle(click, cond, showMessage, hideMessage)
-    .advanced-options
-        i.fa(ng-click=click ng-class='#{cond} ? "fa-chevron-circle-down" : "fa-chevron-circle-right"')
-        a(ng-click=click) {{#{cond} ? '#{hideMessage}' : '#{showMessage}'}}
-
-//- Mixin for advanced options toggle with default settings.
-mixin advanced-options-toggle-default
-    +advanced-options-toggle('toggleExpanded()', 'ui.expanded', 'Show advanced settings...', 'Hide advanced settings...')
-
-//- Mixin for main table on screen with list of items.
-mixin main-table(title, rows, focusId, click, rowTemplate, searchField)
-    .padding-bottom-dflt(ng-show='#{rows} && #{rows}.length > 0')
-        table.links(st-table='displayedRows' st-safe-src='#{rows}')
-            thead
-                tr
-                    th
-                        lable.labelHeader.labelFormField #{title}:
-                        .col-sm-3.pull-right(style='padding: 0')
-                            input.form-control(type='text' st-search='#{searchField}' placeholder='Filter #{title}...')
-            tbody
-                tr
-                    td
-                        .scrollable-y(ng-show='displayedRows.length > 0' style='max-height: 200px')
-                            table
-                                tbody
-                                    tr(ng-repeat='row in displayedRows track by row._id' ignite-bs-affix-update)
-                                        td
-                                            a(ng-class='{active: row._id == selectedItem._id}' ignite-on-click-focus=focusId ng-click=click) #{rowTemplate}
-                        label.placeholder(ng-show='displayedRows.length == 0') No #{title} found
-
-//- Mixin with save, remove, clone and undo buttons.
-mixin save-remove-clone-undo-buttons(objectName)
-    -var removeTip = '"Remove current ' + objectName + '"'
-    -var cloneTip = '"Clone current ' + objectName + '"'
-    -var undoTip = '"Undo all changes for current ' + objectName + '"'
-
-    div(ng-show='contentVisible()' style='display: inline-block;')
-        .panel-tip-container(ng-hide='!backupItem || backupItem._id')
-            a.btn.btn-primary(ng-disabled='!ui.inputForm.$dirty' ng-click='ui.inputForm.$dirty && saveItem()' bs-tooltip='' data-title='{{saveBtnTipText(ui.inputForm.$dirty, "#{objectName}")}}' data-placement='bottom' data-trigger='hover') Save
-        .panel-tip-container(ng-show='backupItem._id')
-            a.btn.btn-primary(id='save-item' ng-disabled='!ui.inputForm.$dirty' ng-click='ui.inputForm.$dirty && saveItem()' bs-tooltip='' data-title='{{saveBtnTipText(ui.inputForm.$dirty, "#{objectName}")}}' data-placement='bottom' data-trigger='hover') Save
-        .panel-tip-container(ng-show='backupItem._id')
-            a.btn.btn-primary(id='clone-item' ng-click='cloneItem()' bs-tooltip=cloneTip data-placement='bottom' data-trigger='hover') Clone
-        .btn-group.panel-tip-container(ng-show='backupItem._id')
-            button.btn.btn-primary(id='remove-item' ng-click='removeItem()' bs-tooltip=removeTip data-placement='bottom' data-trigger='hover') Remove
-            button.btn.dropdown-toggle.btn-primary(id='remove-item-dropdown' data-toggle='dropdown' data-container='body' bs-dropdown='[{ text: "Remove All", click: "removeAllItems()" }]' data-placement='bottom-right')
-                span.caret
-        .panel-tip-container(ng-show='backupItem')
-            i.btn.btn-primary.fa.fa-undo(id='undo-item' ng-disabled='!ui.inputForm.$dirty' ng-click='ui.inputForm.$dirty && resetAll()' bs-tooltip=undoTip data-placement='bottom' data-trigger='hover')
-
-//- Mixin for feedback on specified error.
-mixin error-feedback(visible, error, errorMessage, name)
-    i.fa.fa-exclamation-triangle.form-control-feedback(
-        ng-if=visible
-        bs-tooltip='"#{errorMessage}"'
-        ignite-error=error
-        ignite-error-message=errorMessage
-        name=name
-    )
-
-//- Mixin for feedback on unique violation.
-mixin unique-feedback(visible, errorMessage)
-    +error-feedback(visible, 'igniteUnique', errorMessage)
-
-//- Mixin for feedback on IP address violation.
-mixin ipaddress-feedback(visible, name)
-    +error-feedback(visible, 'ipaddress', 'Invalid address!', name)
-
-//- Mixin for feedback on port of IP address violation.
-mixin ipaddress-port-feedback(visible, name)
-    +error-feedback(visible, 'ipaddressPort', 'Invalid port!', name)
-
-//- Mixin for feedback on port range violation.
-mixin ipaddress-port-range-feedback(visible, name)
-    +error-feedback(visible, 'ipaddressPortRange', 'Invalid port range!', name)
-
-//- Mixin for checkbox.
-mixin checkbox(lbl, model, name, tip)
-    ignite-form-field.checkbox
-        ignite-form-field-input-checkbox(
-            data-id=name
-            data-name=name
-            data-ng-model=model
-        )
-        | #{lbl}
-        ignite-form-field-tooltip
-            | !{tip}
-
-//- Mixin for checkbox with enabled condition.
-mixin checkbox-enabled(lbl, model, name, enabled, tip)
-    ignite-form-field.checkbox
-        ignite-form-field-input-checkbox(
-            data-id=name
-            data-name=name
-            data-ng-model=model
-            data-ng-disabled='!(#{enabled})'
-        )
-        | #{lbl}
-        ignite-form-field-tooltip
-            | !{tip}
-
-//- Mixin for java name field with enabled condition.
-mixin java-class(lbl, model, name, enabled, required, tip)
-    -var errLbl = lbl.substring(0, lbl.length - 1)
-
-    ignite-form-field
-        ignite-form-field-label
-            | #{lbl}
-        ignite-form-field-tooltip
-            | !{tip}
-        ignite-form-field-input-text(
-            data-id=name
-            data-name=name
-            data-ng-model=model
-            data-ng-disabled='!(#{enabled})'
-            data-ng-required=required
-            data-placeholder='Enter fully qualified class name'
-
-            data-java-identifier='true'
-            data-java-package-specified='true'
-            data-java-keywords='true'
-            data-java-built-in-class='true'
-        )
-            +error-feedback('form[ngModelName].$error.javaBuiltInClass', 'javaBuiltInClass', errLbl + ' should not be the Java built-in class!', name)
-            +error-feedback('form[ngModelName].$error.javaKeywords', 'javaKeywords', errLbl + ' could not contains reserved Java keyword!', name)
-            +error-feedback('form[ngModelName].$error.javaPackageSpecified', 'javaPackageSpecified', errLbl + ' does not have package specified!', name)
-            +error-feedback('form[ngModelName].$error.javaIdentifier', 'javaIdentifier', errLbl + ' is invalid Java identifier!', name)
-
-//- Mixin for text field with enabled condition with options.
-mixin java-class-typeahead(lbl, model, name, options, enabled, required, placeholder, tip)
-    -var errLbl = lbl.substring(0, lbl.length - 1)
-
-    ignite-form-field
-        ignite-form-field-label
-            | #{lbl}
-        ignite-form-field-tooltip
-            | !{tip}
-        ignite-form-field-input-datalist(
-            data-id=name
-            data-name=name
-            data-ng-model=model
-            data-options=options
-            data-placeholder=placeholder
-            data-ng-disabled='!(#{enabled})'
-            data-ng-required=required
-
-            data-java-identifier='true'
-            data-java-package-specified='allow-built-in'
-            data-java-keywords='true'
-        )
-            +error-feedback('form[ngModelName].$error.javaKeywords', 'javaKeywords', errLbl + ' could not contains reserved Java keyword!', name)
-            +error-feedback('form[ngModelName].$error.javaPackageSpecified', 'javaPackageSpecified', errLbl + ' does not have package specified!', name)
-            +error-feedback('form[ngModelName].$error.javaIdentifier', 'javaIdentifier', errLbl + ' is invalid Java identifier!', name)
-
-//- Mixin for text field with IP address check.
-mixin text-ip-address(lbl, model, name, enabled, placeholder, tip)
-    ignite-form-field
-        ignite-form-field-label
-            | #{lbl}
-        ignite-form-field-tooltip
-            | !{tip}
-        ignite-form-field-input-text(
-            data-id=name
-            data-name=name
-            data-ng-model=model
-            data-ipaddress='true'
-            data-ng-disabled='!(#{enabled})'
-            data-placeholder=placeholder
-        )
-            +ipaddress-feedback('form[ngModelName].$error.ipaddress', name)
-
-
-//- Mixin for text field with IP address and port check.
-mixin text-ip-address-with-port(lbl, model, name, enabled, placeholder, tip)
-    ignite-form-field
-        ignite-form-field-label
-            | #{lbl}
-        ignite-form-field-tooltip
-            | !{tip}
-        ignite-form-field-input-text(
-            data-id=name
-            data-name=name
-            data-ng-model=model
-            data-ipaddress='true'
-            data-ipaddress-with-port='true'
-            data-ng-disabled='!(#{enabled})'
-            data-placeholder=placeholder
-        )
-            +ipaddress-feedback('form[ngModelName].$error.ipaddress', name)
-            +ipaddress-port-feedback('form[ngModelName].$error.ipaddressPort', name)
-
-//- Mixin for text field.
-mixin text-enabled(lbl, model, name, enabled, required, placeholder, tip)
-    ignite-form-field
-        ignite-form-field-label
-            | #{lbl}
-        ignite-form-field-tooltip
-            | !{tip}
-        ignite-form-field-input-text(
-            data-id=name
-            data-name=name
-            data-ng-model=model
-            data-placeholder=placeholder
-            data-ng-disabled='!(#{enabled})'
-            data-ng-required=required
-        )
-
-//- Mixin for text field.
-mixin text(lbl, model, name, required, placeholder, tip)
-    +text-enabled(lbl, model, name, 'true', required, placeholder, tip)
-
-//- Mixin for text field with enabled condition with options.
-mixin text-options(lbl, model, name, options, enabled, required, placeholder, tip)
-    ignite-form-field
-        ignite-form-field-label
-            | #{lbl}
-        ignite-form-field-tooltip
-            | !{tip}
-        ignite-form-field-input-datalist(
-            data-id=name
-            data-name=name
-            data-ng-model=model
-            data-options=options
-            data-placeholder=placeholder
-            data-ng-disabled='!(#{enabled})'
-            data-ng-required=required
-        )
-
-//- Mixin for required numeric field.
-mixin number-required(lbl, model, name, enabled, required, placeholder, min, tip)
-    ignite-form-field
-        ignite-form-field-label
-            | #{lbl}
-        ignite-form-field-tooltip
-            | !{tip}
-        ignite-form-field-input-number(
-            data-id=name
-            data-name=name
-            data-ng-model=model
-            data-ng-required=required
-            data-ng-disabled='!(#{enabled})'
-            data-placeholder=placeholder
-            data-min=min
-        )
-
-//- Mixin for required numeric field with maximum and minimum limit.
-mixin number-min-max(lbl, model, name, enabled, placeholder, min, max, tip)
-    +number-min-max-step(lbl, model, name, enabled, placeholder, min, max, '1', tip)
-
-//- Mixin for required numeric field with maximum and minimum limit.
-mixin number-min-max-step(lbl, model, name, enabled, placeholder, min, max, step, tip)
-    ignite-form-field
-        ignite-form-field-label
-            | #{lbl}
-        ignite-form-field-tooltip
-            | !{tip}
-        ignite-form-field-input-number(
-            data-id=name
-            data-name=name
-            data-ng-model=model
-            data-ng-disabled='!(#{enabled})'
-            data-placeholder=placeholder
-            data-min=min
-            data-max=max
-            data-step=step
-        )
-
-//- Mixin for numeric field.
-mixin number(lbl, model, name, enabled, placeholder, min, tip)
-    +number-required(lbl, model, name, enabled, 'false', placeholder, min, tip)
-
-//- Mixin for required dropdown field.
-mixin dropdown-required-empty(lbl, model, name, enabled, required, placeholder, placeholderEmpty, options, tip)
-    ignite-form-field
-        ignite-form-field-label
-            | #{lbl}
-        ignite-form-field-tooltip
-            | !{tip}
-        ignite-form-field-dropdown(
-            data-id=name
-            data-name=name
-            data-options=options
-            data-ng-model=model
-            data-ng-disabled='!(#{enabled})'
-            data-ng-required=required
-            data-placeholder='{{#{options}.length > 0 ? "#{placeholder}" : "#{placeholderEmpty}"}}'
-        )
-
-//- Mixin for required dropdown field.
-mixin dropdown-required(lbl, model, name, enabled, required, placeholder, options, tip)
-    ignite-form-field
-        ignite-form-field-label
-            | #{lbl}
-        ignite-form-field-tooltip
-            | !{tip}
-        ignite-form-field-dropdown(
-            data-id=name
-            data-name=name
-            data-options=options
-            data-ng-model=model
-            data-ng-disabled='!(#{enabled})'
-            data-ng-required=required
-            data-placeholder=placeholder
-        )
-
-//- Mixin for dropdown field.
-mixin dropdown(lbl, model, name, enabled, placeholder, options, tip)
-    +dropdown-required(lbl, model, name, enabled, 'false', placeholder, options, tip)
-
-//- Mixin for dropdown-multiple field.
-mixin dropdown-multiple(lbl, model, name, enabled, placeholder, placeholderEmpty, options, tip)
-    ignite-form-field
-        ignite-form-field-label
-            | !{lbl}
-        ignite-form-field-tooltip
-            | !{tip}
-        ignite-form-field-dropdown(
-            data-id=name
-            data-name=name
-            data-multiple='true'
-            data-options=options
-            data-ng-model=model
-            data-ng-disabled='!(#{enabled})'
-            data-placeholder='{{ #{options}.length > 0 ? "#{placeholder}" : "#{placeholderEmpty}" }}'
-            data-disabled='!#{options}.length'
-        )
-
-//- Mixin for table text field.
-mixin table-text-field(field, items, valid, save, placeholder, newItem)
-    -var resetOnEnter = newItem ? '(stopblur = true) && (group.add = [{}])' : '(field.edit = false)'
-    -var onEnter = valid + ' && (' + save + '); ' + valid + ' && ' + resetOnEnter + ';'
-
-    -var onEscape = newItem ? 'group.add = []' : 'field.edit = false'
-
-    -var resetOnBlur = newItem ? '!stopblur && (group.add = [])' : 'field.edit = false'
-    -var onBlur = valid + ' && ( ' + save + '); ' + resetOnBlur + ';'
-
-    ignite-form-field-input-text(
-        data-name='#{field}{{ $index || "" }}'
-        data-ng-model=field
-        data-ng-required='true'
-        data-placeholder=placeholder
-        data-ignite-unique=items
-        data-ignite-form-field-input-autofocus='true'
-        ignite-on-enter=onEnter
-        ignite-on-escape=onEscape
-        ng-blur=onBlur
-    )
-        block
-
-//- Mixin for table java class field.
-mixin table-java-class-field(lbl, field, items, valid, save, newItem)
-    -var resetOnEnter = newItem ? '(stopblur = true) && (group.add = [{}])' : '(field.edit = false)'
-    -var onEnter = valid + ' && (' + save + '); ' + valid + ' && ' + resetOnEnter + ';'
-
-    -var onEscape = newItem ? 'group.add = []' : 'field.edit = false'
-
-    -var resetOnBlur = newItem ? '!stopblur && (group.add = [])' : 'field.edit = false'
-    -var onBlur = valid + ' && ( ' + save + '); ' + resetOnBlur + ';'
-
-    ignite-form-field-input-text(
-        data-name='#{field}{{ $index || "" }}'
-        data-ng-model=field
-        data-ng-required='true'
-        data-ignite-unique=items
-        data-ignite-form-field-input-autofocus='true'
-
-        data-java-identifier='true'
-        data-java-package-specified='true'
-        data-java-keywords='true'
-        data-java-built-in-class='true'
-
-        data-placeholder='Enter fully qualified class name'
-
-        ignite-on-enter=onEnter
-        ignite-on-escape=onEscape
-        ng-blur=onBlur
-    )
-        +error-feedback('form[ngModelName].$error.javaBuiltInClass', 'javaBuiltInClass', lbl + ' should not be the Java built-in class!')
-        +error-feedback('form[ngModelName].$error.javaKeywords', 'javaKeywords', lbl + ' could not contains reserved Java keyword!')
-        +error-feedback('form[ngModelName].$error.javaPackageSpecified', 'javaPackageSpecified', lbl + ' does not have package specified!')
-        +error-feedback('form[ngModelName].$error.javaIdentifier', 'javaIdentifier', lbl + ' is invalid Java identifier!')
-
-        block
-
-//- Mixin for table java package field.
-mixin table-java-package-field(field, items, valid, save, newItem)
-    -var resetOnEnter = newItem ? '(stopblur = true) && (group.add = [{}])' : '(field.edit = false)'
-    -var onEnter = valid + ' && (' + save + '); ' + valid + ' && ' + resetOnEnter + ';'
-
-    -var onEscape = newItem ? 'group.add = []' : 'field.edit = false'
-
-    -var resetOnBlur = newItem ? '!stopblur && (group.add = [])' : 'field.edit = false'
-    -var onBlur = valid + ' && ( ' + save + '); ' + resetOnBlur + ';'
-
-    ignite-form-field-input-text(
-        data-name='#{field}{{ $index || "" }}'
-        data-ng-model=field
-        data-ng-required='true'
-        data-placeholder='Enter package name'
-        data-java-keywords='true'
-        data-java-package-name='true'
-        data-ignite-unique=items
-        data-ignite-form-field-input-autofocus='true'
-        ignite-on-enter=onEnter
-        ignite-on-escape=onEscape
-        ng-blur=onBlur
-    )
-        block
-
-//- Mixin for table address field.
-mixin table-address-field(field, items, valid, save, newItem, portRange)
-    -var resetOnEnter = newItem ? '(stopblur = true) && (group.add = [{}])' : '(field.edit = false)'
-    -var onEnter = valid + ' && (' + save + '); ' + valid + ' && ' + resetOnEnter + ';'
-
-    -var onEscape = newItem ? 'group.add = []' : 'field.edit = false'
-
-    -var resetOnBlur = newItem ? '!stopblur && (group.add = [])' : 'field.edit = false'
-    -var onBlur = valid + ' && ( ' + save + '); ' + resetOnBlur + ';'
-
-    ignite-form-field-input-text(
-        data-name='#{field}{{ $index || "" }}'
-        data-ng-model=field
-        data-ng-required='true'
-        data-placeholder='IP address:port'
-        data-ipaddress='true'
-        data-ipaddress-with-port='true'
-        data-ipaddress-with-port-range=portRange ? 'true' : null
-        data-ignite-unique=items
-        data-ignite-form-field-input-autofocus='true'
-        ignite-on-enter=onEnter
-        ignite-on-escape=onEscape
-        ng-blur=onBlur
-    )
-        block
-
-//- Mixin for table save button.
-   "||" used instead of "&&" to workaround escaping of "&&" to "&amp;&amp;"
-mixin table-save-button(valid, save, newItem)
-    -var reset = newItem ? 'group.add = []' : 'field.edit = false'
-
-    i.fa.fa-floppy-o(
-        ng-show=valid
-        ng-click='!(#{valid}) || (#{save}); !(#{valid}) || (#{reset});'
-        bs-tooltip
-        data-title='Click icon or press [Enter] to save item'
-    )
-
-//- Mixin for table remove button.
-mixin table-remove-conditional-button(items, show, tip)
-    i.tipField.fa.fa-remove(
-        ng-hide='!#{show} || field.edit'
-        bs-tooltip
-        data-title=tip
-        ng-click='#{items}.splice(#{items}.indexOf(model), 1)'
-    )
-
-//- Mixin for table remove button.
-mixin table-remove-button(items, tip)
-    +table-remove-conditional-button(items, 'true', tip)
-
-//- Mixin for cache mode.
-mixin cacheMode(lbl, model, name, placeholder)
-    +dropdown(lbl, model, name, 'true', placeholder,
-        '[\
-            {value: "LOCAL", label: "LOCAL"},\
-            {value: "REPLICATED", label: "REPLICATED"},\
-            {value: "PARTITIONED", label: "PARTITIONED"}\
-        ]',
-        'Cache modes:\
-        <ul>\
-            <li>Partitioned - in this mode the overall key set will be divided into partitions and all partitions will be split equally between participating nodes</li>\
-            <li>Replicated - in this mode all the keys are distributed to all participating nodes</li>\
-            <li>Local - in this mode caches residing on different grid nodes will not know about each other</li>\
-        </ul>'
-    )
-
-//- Mixin for eviction policy.
-mixin evictionPolicy(model, name, enabled, required, tip)
-    -var kind = model + '.kind'
-    -var policy = model + '[' + kind + ']'
-
-    +dropdown-required('Eviction policy:', kind, name + 'Kind', enabled, required, 'Not set',
-        '[\
-            {value: "LRU", label: "LRU"},\
-            {value: "FIFO", label: "FIFO"},\
-            {value: "SORTED", label: "Sorted"},\
-            {value: undefined, label: "Not set"}\
-        ]', tip)
-    span(ng-if=kind)
-        a.customize(ng-show='__.expanded' ng-click='__.expanded = false') Hide settings
-        a.customize(ng-hide='__.expanded' ng-click='__.expanded = true') Show settings
-        .panel-details(ng-if='__.expanded')
-            .details-row
-                +number('Batch size', policy + '.batchSize', name + 'batchSize', enabled, '1', '0',
-                    'Number of entries to remove on shrink')
-            .details-row
-                +number('Max memory size', policy + '.maxMemorySize', name + 'maxMemorySize', enabled, '0', '0',
-                    'Maximum allowed cache size in bytes')
-            .details-row
-                +number('Max size', policy + '.maxSize', name + 'maxSize', enabled, '100000', '0',
-                    'Maximum allowed size of cache before entry will start getting evicted')
-
-//- Mixin for clusters dropdown.
-mixin clusters(model, tip)
-    +dropdown-multiple('<span>Clusters:</span>' + '<a ui-sref="base.configuration.clusters({linkId: linkId()})"> (add)</a>',
-        model + '.clusters', 'clusters', 'true', 'Choose clusters', 'No clusters configured', 'clusters', tip)
-
-//- Mixin for caches dropdown.
-mixin caches(model, tip)
-    +dropdown-multiple('<span>Caches:</span>' + '<a ui-sref="base.configuration.caches({linkId: linkId()})"> (add)</a>',
-        model + '.caches', 'caches', 'true', 'Choose caches', 'No caches configured', 'caches', tip)
-
-//- Mixin for XML and Java preview.
-mixin preview-xml-java(master, generator, detail)
-    ignite-ui-ace-tabs
-        .preview-panel(ng-init='mode = false')
-            .preview-legend
-                a(ng-class='{active: !mode, inactive: mode}' ng-click='mode = false') XML
-                | &nbsp;
-                a(ng-class='{active: mode, inactive: !mode}' ng-click='mode = true') Java
-            .preview-content(ng-if='mode')
-                ignite-ui-ace-java(data-master=master data-generator=generator ng-model='$parent.data' data-detail=detail)
-            .preview-content(ng-if='!mode')
-                ignite-ui-ace-xml(data-master=master data-generator=generator ng-model='$parent.data' data-detail=detail)
-            .preview-content-empty(ng-if='!data')
-                label All Defaults
-
-//- LEGACY mixin for LEGACY tables.
-mixin btn-save(show, click)
-    i.tipField.fa.fa-floppy-o(ng-show=show ng-click=click bs-tooltip='' data-title='Click icon or press [Enter] to save item' data-trigger='hover')
-
-//- LEGACY mixin for LEGACY tables.
-mixin btn-add(click, tip)
-    i.tipField.fa.fa-plus(ng-click=click bs-tooltip=tip data-trigger = 'hover')
-
-//- LEGACY mixin for LEGACY tables.
-mixin btn-remove(click, tip)
-    i.tipField.fa.fa-remove(ng-click=click bs-tooltip=tip data-trigger='hover')
-
-//- LEGACY mixin for LEGACY tables.
-mixin btn-remove-cond(cond, click, tip)
-    i.tipField.fa.fa-remove(ng-show=cond ng-click=click bs-tooltip=tip data-trigger='hover')
-
-//- LEGACY mixin for LEGACY pair values tables.
-mixin table-pair-edit(tbl, prefix, keyPlaceholder, valPlaceholder, keyJavaBuiltInTypes, valueJavaBuiltInTypes, focusId, index, divider)
-    -var keyModel = tbl + '.' + prefix + 'Key'
-    -var valModel = tbl +'.' + prefix + 'Value'
-
-    -var keyFocusId = prefix + 'Key' + focusId
-    -var valFocusId = prefix + 'Value' + focusId
-
-    .col-xs-6.col-sm-6.col-md-6
-        .fieldSep !{divider}
-        .input-tip
-            if keyJavaBuiltInTypes
-                input.form-control(id=keyFocusId ignite-on-enter-focus-move=valFocusId type='text' ng-model=keyModel placeholder=keyPlaceholder bs-typeahead container='body' ignite-retain-selection data-min-length='1' bs-options='javaClass for javaClass in javaBuiltInClasses' ignite-on-escape='tableReset()')
-            else
-                input.form-control(id=keyFocusId ignite-on-enter-focus-move=valFocusId type='text' ng-model=keyModel placeholder=keyPlaceholder ignite-on-escape='tableReset()')
-    .col-xs-6.col-sm-6.col-md-6
-        -var arg = keyModel + ', ' + valModel
-        -var btnVisible = 'tablePairSaveVisible(' + tbl + ', ' + index + ')'
-        -var btnSave = 'tablePairSave(tablePairValid, backupItem, ' + tbl + ', ' + index + ')'
-        -var btnVisibleAndSave = btnVisible + ' && ' + btnSave
-
-        +btn-save(btnVisible, btnSave)
-        .input-tip
-            if valueJavaBuiltInTypes
-                input.form-control(id=valFocusId type='text' ng-model=valModel placeholder=valPlaceholder bs-typeahead container='body' ignite-retain-selection data-min-length='1' bs-options='javaClass for javaClass in javaBuiltInClasses' ignite-on-enter=btnVisibleAndSave ignite-on-escape='tableReset()')
-            else
-                input.form-control(id=valFocusId type='text' ng-model=valModel placeholder=valPlaceholder ignite-on-enter=btnVisibleAndSave ignite-on-escape='tableReset()')

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/src/main/js/app/modules/Demo/Demo.module.js
----------------------------------------------------------------------
diff --git a/modules/web-console/src/main/js/app/modules/Demo/Demo.module.js b/modules/web-console/src/main/js/app/modules/Demo/Demo.module.js
deleted file mode 100644
index 68aca9d..0000000
--- a/modules/web-console/src/main/js/app/modules/Demo/Demo.module.js
+++ /dev/null
@@ -1,166 +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 angular from 'angular';
-
-import DEMO_INFO from 'app/data/demo-info.json';
-
-angular
-.module('ignite-console.demo', [
-    'ignite-console.socket'
-])
-.config(['$stateProvider', ($stateProvider) => {
-    $stateProvider
-        .state('demo', {
-            abstract: true,
-            template: '<ui-view></ui-view>'
-        })
-        .state('demo.resume', {
-            url: '/demo',
-            controller: ['$state', ($state) => {
-                $state.go('base.configuration.clusters');
-            }],
-            metaTags: {
-            }
-        })
-        .state('demo.reset', {
-            url: '/demo/reset',
-            controller: ['$state', '$http', 'IgniteMessages', ($state, $http, Messages) => {
-                $http.post('/api/v1/demo/reset')
-                    .then(() => $state.go('base.configuration.clusters'))
-                    .catch((err) => {
-                        $state.go('base.configuration.clusters');
-
-                        Messages.showError(err);
-                    });
-            }],
-            metaTags: {}
-        });
-}])
-.provider('Demo', ['$stateProvider', '$httpProvider', 'igniteSocketFactoryProvider', function($state, $http, socketFactory) {
-    if (/(\/demo.*)/ig.test(location.pathname))
-        sessionStorage.setItem('IgniteDemoMode', 'true');
-
-    const enabled = sessionStorage.getItem('IgniteDemoMode') === 'true';
-
-    if (enabled) {
-        socketFactory.set({query: 'IgniteDemoMode=true'});
-
-        $http.interceptors.push('demoInterceptor');
-    }
-
-    this.$get = ['$rootScope', ($root) => {
-        $root.IgniteDemoMode = enabled;
-
-        return {enabled};
-    }];
-}])
-.factory('demoInterceptor', ['Demo', (Demo) => {
-    const isApiRequest = (url) => /\/api\/v1/ig.test(url);
-
-    return {
-        request(cfg) {
-            if (Demo.enabled && isApiRequest(cfg.url))
-                cfg.headers.IgniteDemoMode = true;
-
-            return cfg;
-        }
-    };
-}])
-.controller('demoController', ['$scope', '$state', '$window', 'IgniteConfirm', ($scope, $state, $window, Confirm) => {
-    const _openTab = (stateName) => $window.open($state.href(stateName), '_blank');
-
-    $scope.startDemo = () => {
-        if (!$scope.user.demoCreated)
-            return _openTab('demo.reset');
-
-        Confirm.confirm('Would you like to continue with previous demo session?', true, false)
-            .then((resume) => {
-                if (resume)
-                    return _openTab('demo.resume');
-
-                _openTab('demo.reset');
-            });
-    };
-
-    $scope.closeDemo = () => {
-        $window.close();
-    };
-}])
-.provider('igniteDemoInfo', [function() {
-    const items = DEMO_INFO;
-
-    this.update = (data) => items[0] = data;
-
-    this.$get = [() => {
-        return items;
-    }];
-}])
-.service('DemoInfo', ['$rootScope', '$modal', '$state', '$q', 'igniteDemoInfo', 'IgniteAgentMonitor', ($rootScope, $modal, $state, $q, igniteDemoInfo, agentMonitor) => {
-    const scope = $rootScope.$new();
-
-    let closePromise = null;
-
-    function _fillPage() {
-        const model = igniteDemoInfo;
-
-        scope.title = model[0].title;
-        scope.message = model[0].message.join(' ');
-    }
-
-    const dialog = $modal({
-        templateUrl: '/templates/demo-info.html',
-        scope,
-        placement: 'center',
-        show: false,
-        backdrop: 'static'
-    });
-
-    scope.close = () => {
-        dialog.hide();
-
-        closePromise && closePromise.resolve();
-    };
-
-    scope.downloadAgent = () => {
-        const lnk = document.createElement('a');
-
-        lnk.setAttribute('href', '/api/v1/agent/download/zip');
-        lnk.setAttribute('target', '_self');
-        lnk.setAttribute('download', null);
-        lnk.style.display = 'none';
-
-        document.body.appendChild(lnk);
-
-        lnk.click();
-
-        document.body.removeChild(lnk);
-    };
-
-    return {
-        show: () => {
-            closePromise = $q.defer();
-
-            _fillPage();
-
-            return dialog.$promise
-                .then(dialog.show)
-                .then(() => Promise.race([agentMonitor.awaitAgent(), closePromise.promise]))
-                .then(() => scope.hasAgents = true);
-        }
-    };
-}]);

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/src/main/js/app/modules/Version/Version.provider.js
----------------------------------------------------------------------
diff --git a/modules/web-console/src/main/js/app/modules/Version/Version.provider.js b/modules/web-console/src/main/js/app/modules/Version/Version.provider.js
deleted file mode 100644
index fe503ab..0000000
--- a/modules/web-console/src/main/js/app/modules/Version/Version.provider.js
+++ /dev/null
@@ -1,32 +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 angular from 'angular';
-
-angular
-    .module('ignite-console.version', [])
-    .provider('IgniteVersion', function() {
-        const version = {
-            version: '1.6.0'
-        };
-
-        this.update = (newVersion) => {
-            version.version = newVersion;
-        };
-
-        this.$get = [() => version];
-    });


[38/52] ignite git commit: Web Console beta-3.

Posted by ak...@apache.org.
http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/frontend/app/modules/configuration/generator/Pom.service.js
----------------------------------------------------------------------
diff --git a/modules/web-console/frontend/app/modules/configuration/generator/Pom.service.js b/modules/web-console/frontend/app/modules/configuration/generator/Pom.service.js
new file mode 100644
index 0000000..627a1e3
--- /dev/null
+++ b/modules/web-console/frontend/app/modules/configuration/generator/Pom.service.js
@@ -0,0 +1,226 @@
+/*
+ * 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.
+ */
+
+// Java built-in class names.
+import POM_DEPENDENCIES from 'app/data/pom-dependencies.json';
+
+/**
+ * Pom file generation entry point.
+ */
+class GeneratorPom {
+    escapeId(s) {
+        if (typeof (s) !== 'string')
+            return s;
+
+        return s.replace(/[^A-Za-z0-9_\-.]+/g, '_');
+    }
+
+    addProperty(res, tag, val) {
+        res.line('<' + tag + '>' + val + '</' + tag + '>');
+    }
+
+    addDependency(deps, groupId, artifactId, version, jar) {
+        if (!_.find(deps, (dep) => dep.groupId === groupId && dep.artifactId === artifactId))
+            deps.push({groupId, artifactId, version, jar});
+    }
+
+    addResource(res, dir, exclude) {
+        res.startBlock('<resource>');
+        if (dir)
+            this.addProperty(res, 'directory', dir);
+
+        if (exclude) {
+            res.startBlock('<excludes>');
+            this.addProperty(res, 'exclude', exclude);
+            res.endBlock('</excludes>');
+        }
+
+        res.endBlock('</resource>');
+    }
+
+    artifact(res, cluster, igniteVersion) {
+        this.addProperty(res, 'groupId', 'org.apache.ignite');
+        this.addProperty(res, 'artifactId', this.escapeId(cluster.name) + '-project');
+        this.addProperty(res, 'version', igniteVersion);
+
+        res.needEmptyLine = true;
+    }
+
+    dependencies(res, cluster, deps) {
+        if (!res)
+            res = $generatorCommon.builder();
+
+        res.startBlock('<dependencies>');
+
+        _.forEach(deps, (dep) => {
+            res.startBlock('<dependency>');
+
+            this.addProperty(res, 'groupId', dep.groupId);
+            this.addProperty(res, 'artifactId', dep.artifactId);
+            this.addProperty(res, 'version', dep.version);
+
+            if (dep.jar) {
+                this.addProperty(res, 'scope', 'system');
+                this.addProperty(res, 'systemPath', '${project.basedir}/jdbc-drivers/' + dep.jar);
+            }
+
+            res.endBlock('</dependency>');
+        });
+
+        res.endBlock('</dependencies>');
+
+        return res;
+    }
+
+    build(res, cluster, excludeGroupIds) {
+        res.startBlock('<build>');
+        res.startBlock('<resources>');
+        this.addResource(res, 'src/main/java', '**/*.java');
+        this.addResource(res, 'src/main/resources');
+        res.endBlock('</resources>');
+
+        res.startBlock('<plugins>');
+        res.startBlock('<plugin>');
+        this.addProperty(res, 'artifactId', 'maven-dependency-plugin');
+        res.startBlock('<executions>');
+        res.startBlock('<execution>');
+        this.addProperty(res, 'id', 'copy-libs');
+        this.addProperty(res, 'phase', 'test-compile');
+        res.startBlock('<goals>');
+        this.addProperty(res, 'goal', 'copy-dependencies');
+        res.endBlock('</goals>');
+        res.startBlock('<configuration>');
+        this.addProperty(res, 'excludeGroupIds', excludeGroupIds.join(','));
+        this.addProperty(res, 'outputDirectory', 'target/libs');
+        this.addProperty(res, 'includeScope', 'compile');
+        this.addProperty(res, 'excludeTransitive', 'true');
+        res.endBlock('</configuration>');
+        res.endBlock('</execution>');
+        res.endBlock('</executions>');
+        res.endBlock('</plugin>');
+        res.startBlock('<plugin>');
+        this.addProperty(res, 'artifactId', 'maven-compiler-plugin');
+        this.addProperty(res, 'version', '3.1');
+        res.startBlock('<configuration>');
+        this.addProperty(res, 'source', '1.7');
+        this.addProperty(res, 'target', '1.7');
+        res.endBlock('</configuration>');
+        res.endBlock('</plugin>');
+        res.endBlock('</plugins>');
+        res.endBlock('</build>');
+
+        res.endBlock('</project>');
+    }
+
+    /**
+     * Add dependency for specified store factory if not exist.
+     * @param storeDeps Already added dependencies.
+     * @param storeFactory Store factory to add dependency.
+     */
+    storeFactoryDependency(storeDeps, storeFactory) {
+        if (storeFactory.dialect && (!storeFactory.connectVia || storeFactory.connectVia === 'DataSource')) {
+            const dep = POM_DEPENDENCIES[storeFactory.dialect];
+
+            this.addDependency(storeDeps, dep.groupId, dep.artifactId, dep.version, dep.jar);
+        }
+    }
+
+    /**
+     * Generate pom.xml.
+     *
+     * @param cluster Cluster  to take info about dependencies.
+     * @param igniteVersion Ignite version for Ignite dependencies.
+     * @param res Resulting output with generated pom.
+     * @returns {string} Generated content.
+     */
+    generate(cluster, igniteVersion, res) {
+        const caches = cluster.caches;
+        const deps = [];
+        const storeDeps = [];
+        const excludeGroupIds = ['org.apache.ignite'];
+
+        const blobStoreFactory = {cacheStoreFactory: {kind: 'CacheHibernateBlobStoreFactory'}};
+
+        if (!res)
+            res = $generatorCommon.builder();
+
+        _.forEach(caches, (cache) => {
+            if (cache.cacheStoreFactory && cache.cacheStoreFactory.kind)
+                this.storeFactoryDependency(storeDeps, cache.cacheStoreFactory[cache.cacheStoreFactory.kind]);
+
+            if (_.get(cache, 'nodeFilter.kind') === 'Exclude')
+                this.addDependency(deps, 'org.apache.ignite', 'ignite-extdata-p2p', igniteVersion);
+        });
+
+        res.line('<?xml version="1.0" encoding="UTF-8"?>');
+
+        res.needEmptyLine = true;
+
+        res.line('<!-- ' + $generatorCommon.mainComment() + ' -->');
+
+        res.needEmptyLine = true;
+
+        res.startBlock('<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">');
+
+        res.line('<modelVersion>4.0.0</modelVersion>');
+
+        res.needEmptyLine = true;
+
+        this.artifact(res, cluster, igniteVersion);
+
+        this.addDependency(deps, 'org.apache.ignite', 'ignite-core', igniteVersion);
+
+        this.addDependency(deps, 'org.apache.ignite', 'ignite-spring', igniteVersion);
+        this.addDependency(deps, 'org.apache.ignite', 'ignite-indexing', igniteVersion);
+        this.addDependency(deps, 'org.apache.ignite', 'ignite-rest-http', igniteVersion);
+
+        let dep = POM_DEPENDENCIES[cluster.discovery.kind];
+
+        if (dep)
+            this.addDependency(deps, 'org.apache.ignite', dep.artifactId, igniteVersion);
+
+        if (cluster.discovery.kind === 'Jdbc') {
+            const store = cluster.discovery.Jdbc;
+
+            if (store.dataSourceBean && store.dialect)
+                this.storeFactoryDependency(storeDeps, cluster.discovery.Jdbc);
+        }
+
+        if (_.find(cluster.igfss, (igfs) => igfs.secondaryFileSystemEnabled))
+            this.addDependency(deps, 'org.apache.ignite', 'ignite-hadoop', igniteVersion);
+
+        if (_.find(caches, blobStoreFactory))
+            this.addDependency(deps, 'org.apache.ignite', 'ignite-hibernate', igniteVersion);
+
+        if (cluster.logger && cluster.logger.kind) {
+            dep = POM_DEPENDENCIES[cluster.logger.kind];
+
+            if (dep)
+                this.addDependency(deps, 'org.apache.ignite', dep.artifactId, igniteVersion);
+        }
+
+        this.dependencies(res, cluster, deps.concat(storeDeps));
+
+        res.needEmptyLine = true;
+
+        this.build(res, cluster, excludeGroupIds);
+
+        return res;
+    }
+}
+
+export default ['GeneratorPom', GeneratorPom];

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/frontend/app/modules/configuration/generator/Xml.service.js
----------------------------------------------------------------------
diff --git a/modules/web-console/frontend/app/modules/configuration/generator/Xml.service.js b/modules/web-console/frontend/app/modules/configuration/generator/Xml.service.js
new file mode 100644
index 0000000..58d1ce0
--- /dev/null
+++ b/modules/web-console/frontend/app/modules/configuration/generator/Xml.service.js
@@ -0,0 +1,21 @@
+/*
+ * 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.
+ */
+
+// TODO IGNITE-2052: need move $generatorXml to services.
+export default ['GeneratorXml', () => {
+    return $generatorXml;
+}];

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/frontend/app/modules/configuration/sidebar.directive.js
----------------------------------------------------------------------
diff --git a/modules/web-console/frontend/app/modules/configuration/sidebar.directive.js b/modules/web-console/frontend/app/modules/configuration/sidebar.directive.js
new file mode 100644
index 0000000..e51553b
--- /dev/null
+++ b/modules/web-console/frontend/app/modules/configuration/sidebar.directive.js
@@ -0,0 +1,30 @@
+/*
+ * 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 ['igniteSidebar', ['igniteSidebar', (igniteSidebar) => {
+    function controller() {
+        const ctrl = this;
+
+        ctrl.items = igniteSidebar;
+    }
+
+    return {
+        restrict: 'A',
+        controller,
+        controllerAs: 'sidebar'
+    };
+}]];

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/frontend/app/modules/dialog/dialog-content.directive.js
----------------------------------------------------------------------
diff --git a/modules/web-console/frontend/app/modules/dialog/dialog-content.directive.js b/modules/web-console/frontend/app/modules/dialog/dialog-content.directive.js
new file mode 100644
index 0000000..98e9903
--- /dev/null
+++ b/modules/web-console/frontend/app/modules/dialog/dialog-content.directive.js
@@ -0,0 +1,31 @@
+/*
+ * 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 ['igniteDialogContent', [() => {
+    const link = ($scope, $element, $attrs, igniteDialog) => {
+        igniteDialog.content = $element.html();
+
+        $element.hide();
+    };
+
+    return {
+        scope: {},
+        restrict: 'E',
+        link,
+        require: '^igniteDialog'
+    };
+}]];

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/frontend/app/modules/dialog/dialog-title.directive.js
----------------------------------------------------------------------
diff --git a/modules/web-console/frontend/app/modules/dialog/dialog-title.directive.js b/modules/web-console/frontend/app/modules/dialog/dialog-title.directive.js
new file mode 100644
index 0000000..ed4adb8
--- /dev/null
+++ b/modules/web-console/frontend/app/modules/dialog/dialog-title.directive.js
@@ -0,0 +1,31 @@
+/*
+ * 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 ['igniteDialogTitle', [() => {
+    const link = ($scope, $element, $attrs, igniteDialog) => {
+        igniteDialog.title = $element.text();
+
+        $element.hide();
+    };
+
+    return {
+        scope: {},
+        restrict: 'E',
+        link,
+        require: '^igniteDialog'
+    };
+}]];

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/frontend/app/modules/dialog/dialog.controller.js
----------------------------------------------------------------------
diff --git a/modules/web-console/frontend/app/modules/dialog/dialog.controller.js b/modules/web-console/frontend/app/modules/dialog/dialog.controller.js
new file mode 100644
index 0000000..05518d3
--- /dev/null
+++ b/modules/web-console/frontend/app/modules/dialog/dialog.controller.js
@@ -0,0 +1,40 @@
+/*
+ * 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 ['$rootScope', '$scope', 'IgniteDialog', function($root, $scope, IgniteDialog) {
+    const ctrl = this;
+
+    const dialog = new IgniteDialog({
+        scope: $scope
+    });
+
+    ctrl.show = () => {
+        dialog.$promise.then(dialog.show);
+    };
+
+    $scope.$watch(() => ctrl.title, () => {
+        $scope.title = ctrl.title;
+    });
+
+    $scope.$watch(() => ctrl.content, () => {
+        $scope.content = ctrl.content;
+    });
+
+    $root.$on('$stateChangeStart', () => {
+        dialog.hide();
+    });
+}];

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/frontend/app/modules/dialog/dialog.directive.js
----------------------------------------------------------------------
diff --git a/modules/web-console/frontend/app/modules/dialog/dialog.directive.js b/modules/web-console/frontend/app/modules/dialog/dialog.directive.js
new file mode 100644
index 0000000..7aab10f
--- /dev/null
+++ b/modules/web-console/frontend/app/modules/dialog/dialog.directive.js
@@ -0,0 +1,32 @@
+/*
+ * 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 controller from './dialog.controller';
+
+const template = '<a ng-click="ctrl.show()"><span ng-transclude=""></span></a>';
+
+export default ['igniteDialog', [() => {
+    return {
+        restrict: 'E',
+        template,
+        controller,
+        controllerAs: 'ctrl',
+        replace: true,
+        transclude: true,
+        require: '^igniteDialog'
+    };
+}]];

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/frontend/app/modules/dialog/dialog.factory.js
----------------------------------------------------------------------
diff --git a/modules/web-console/frontend/app/modules/dialog/dialog.factory.js b/modules/web-console/frontend/app/modules/dialog/dialog.factory.js
new file mode 100644
index 0000000..e15891f
--- /dev/null
+++ b/modules/web-console/frontend/app/modules/dialog/dialog.factory.js
@@ -0,0 +1,32 @@
+/*
+ * 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 templateUrl from './dialog.jade';
+
+export default ['IgniteDialog', ['$modal', ($modal) => {
+    const defaults = {
+        templateUrl,
+        placement: 'center',
+        show: false
+    };
+
+    return function(options) {
+        options = _.extend({}, defaults, options);
+
+        return $modal(options);
+    };
+}]];

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/frontend/app/modules/dialog/dialog.jade
----------------------------------------------------------------------
diff --git a/modules/web-console/frontend/app/modules/dialog/dialog.jade b/modules/web-console/frontend/app/modules/dialog/dialog.jade
new file mode 100644
index 0000000..0043709
--- /dev/null
+++ b/modules/web-console/frontend/app/modules/dialog/dialog.jade
@@ -0,0 +1,26 @@
+//-
+    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.
+
+.modal(tabindex='-1' role='dialog')
+    .modal-dialog
+        .modal-content
+            .modal-header
+                button.close(ng-click='$hide()' aria-hidden='true') &times;
+                h4.modal-title {{title}}
+            .modal-body(ng-show='content')
+                p(ng-bind-html='content' style='text-align: left;')
+            .modal-footer
+                button.btn.btn-primary(id='confirm-btn-confirm' ng-click='$hide()') Ok

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/frontend/app/modules/dialog/dialog.module.js
----------------------------------------------------------------------
diff --git a/modules/web-console/frontend/app/modules/dialog/dialog.module.js b/modules/web-console/frontend/app/modules/dialog/dialog.module.js
new file mode 100644
index 0000000..c9ba9f9
--- /dev/null
+++ b/modules/web-console/frontend/app/modules/dialog/dialog.module.js
@@ -0,0 +1,32 @@
+/*
+ * 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 igniteDialog from './dialog.directive';
+import igniteDialogTitle from './dialog-title.directive';
+import igniteDialogContent from './dialog-content.directive';
+import IgniteDialog from './dialog.factory';
+
+angular
+.module('ignite-console.dialog', [
+
+])
+.factory(...IgniteDialog)
+.directive(...igniteDialog)
+.directive(...igniteDialogTitle)
+.directive(...igniteDialogContent);

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/frontend/app/modules/form/field/bs-select-placeholder.directive.js
----------------------------------------------------------------------
diff --git a/modules/web-console/frontend/app/modules/form/field/bs-select-placeholder.directive.js b/modules/web-console/frontend/app/modules/form/field/bs-select-placeholder.directive.js
new file mode 100644
index 0000000..83f438d
--- /dev/null
+++ b/modules/web-console/frontend/app/modules/form/field/bs-select-placeholder.directive.js
@@ -0,0 +1,47 @@
+/*
+ * 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.
+ */
+
+// Override AngularStrap "bsSelect" in order to dynamically change placeholder and class.
+export default ['bsSelect', [() => {
+    const link = (scope, $element, attrs, [ngModel]) => {
+        if (!ngModel)
+            return;
+
+        const $render = ngModel.$render;
+
+        ngModel.$render = () => {
+            $render();
+
+            const value = ngModel.$viewValue;
+
+            if (_.isNil(value) || (attrs.multiple && !value.length)) {
+                $element.html(attrs.placeholder);
+
+                $element.addClass('placeholder');
+            }
+            else
+                $element.removeClass('placeholder');
+        };
+    };
+
+    return {
+        priority: 1,
+        restrict: 'A',
+        link,
+        require: ['?ngModel']
+    };
+}]];

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/frontend/app/modules/form/field/down.directive.js
----------------------------------------------------------------------
diff --git a/modules/web-console/frontend/app/modules/form/field/down.directive.js b/modules/web-console/frontend/app/modules/form/field/down.directive.js
new file mode 100644
index 0000000..659933e
--- /dev/null
+++ b/modules/web-console/frontend/app/modules/form/field/down.directive.js
@@ -0,0 +1,39 @@
+/*
+ * 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 ['igniteFormFieldDown', ['$tooltip', ($tooltip) => {
+    const controller = ['$element', function($element) {
+        $tooltip($element, { title: 'Move item down' });
+
+        this.down = () => {
+            const i = this.models.indexOf(this.model);
+
+            this.models.splice(i, 1);
+            this.models.splice(i + 1, 0, this.model);
+        };
+    }];
+
+    return {
+        restrict: 'A',
+        bindToController: {
+            model: '=ngModel',
+            models: '=models'
+        },
+        controller,
+        controllerAs: '$ctrl'
+    };
+}]];

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/frontend/app/modules/form/field/feedback.scss
----------------------------------------------------------------------
diff --git a/modules/web-console/frontend/app/modules/form/field/feedback.scss b/modules/web-console/frontend/app/modules/form/field/feedback.scss
new file mode 100644
index 0000000..08d0aef
--- /dev/null
+++ b/modules/web-console/frontend/app/modules/form/field/feedback.scss
@@ -0,0 +1,37 @@
+/*
+ * 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 "../../../../public/stylesheets/variables";
+
+.form-field-feedback {
+    position: relative;
+    width: 0;
+    height: 28px;
+    float: right;
+    z-index: 2;
+
+    color: $brand-primary;
+    line-height: $input-height;
+    pointer-events: initial;
+    text-align: center;
+
+    &:before {
+        position: absolute;
+        right: 0;
+        width: 38px;
+    }
+}

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/frontend/app/modules/form/field/field.scss
----------------------------------------------------------------------
diff --git a/modules/web-console/frontend/app/modules/form/field/field.scss b/modules/web-console/frontend/app/modules/form/field/field.scss
new file mode 100644
index 0000000..5717766
--- /dev/null
+++ b/modules/web-console/frontend/app/modules/form/field/field.scss
@@ -0,0 +1,43 @@
+/*
+ * 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 "../../../../public/stylesheets/variables";
+
+.indexField {
+    float: left;
+    line-height: 28px;
+    margin-right: 5px;
+    color: $brand-primary;
+}
+
+.form-field-save {
+    position: relative;
+    width: 0;
+    height: 28px;
+    float: right;
+    z-index: 2;
+
+    line-height: $input-height;
+    pointer-events: initial;
+    text-align: center;
+
+    &:before {
+        position: absolute;
+        right: 0;
+        width: 38px;
+    }    
+}

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/frontend/app/modules/form/field/form-control-feedback.directive.js
----------------------------------------------------------------------
diff --git a/modules/web-console/frontend/app/modules/form/field/form-control-feedback.directive.js b/modules/web-console/frontend/app/modules/form/field/form-control-feedback.directive.js
new file mode 100644
index 0000000..797ba69
--- /dev/null
+++ b/modules/web-console/frontend/app/modules/form/field/form-control-feedback.directive.js
@@ -0,0 +1,40 @@
+/*
+ * 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 ['formFieldFeedback', [() => {
+    const link = ($scope, $element, $attrs, [form]) => {
+        let name = $scope.name;
+
+        if (_.isNil(name))
+            name = $attrs.name;
+
+        const err = $attrs.igniteError;
+        const msg = $attrs.igniteErrorMessage;
+
+        if (name && err && msg) {
+            form.$errorMessages = form.$errorMessages || {};
+            form.$errorMessages[name] = form.$errorMessages[name] || {};
+            form.$errorMessages[name][err] = msg;
+        }
+    };
+
+    return {
+        restrict: 'C',
+        link,
+        require: ['^form']
+    };
+}]];

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/frontend/app/modules/form/field/input/autofocus.directive.js
----------------------------------------------------------------------
diff --git a/modules/web-console/frontend/app/modules/form/field/input/autofocus.directive.js b/modules/web-console/frontend/app/modules/form/field/input/autofocus.directive.js
new file mode 100644
index 0000000..8ffc9a0
--- /dev/null
+++ b/modules/web-console/frontend/app/modules/form/field/input/autofocus.directive.js
@@ -0,0 +1,30 @@
+/*
+ * 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 ['igniteFormFieldInputAutofocus', ['$timeout', ($timeout) => {
+    const link = (scope, el, attrs) => {
+        if (_.isUndefined(attrs.igniteFormFieldInputAutofocus) || attrs.igniteFormFieldInputAutofocus !== 'true')
+            return;
+
+        $timeout(() => el.focus(), 100);
+    };
+
+    return {
+        restrict: 'A',
+        link
+    };
+}]];

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/frontend/app/modules/form/field/input/select.scss
----------------------------------------------------------------------
diff --git a/modules/web-console/frontend/app/modules/form/field/input/select.scss b/modules/web-console/frontend/app/modules/form/field/input/select.scss
new file mode 100644
index 0000000..55bbd58
--- /dev/null
+++ b/modules/web-console/frontend/app/modules/form/field/input/select.scss
@@ -0,0 +1,21 @@
+/*
+ * 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.
+ */
+
+.select.dropdown-menu.ng-leave {
+    transition: none !important; /* disable transitions */
+    animation: none 0s !important; /* disable keyframe animations */
+}

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/frontend/app/modules/form/field/input/text.scss
----------------------------------------------------------------------
diff --git a/modules/web-console/frontend/app/modules/form/field/input/text.scss b/modules/web-console/frontend/app/modules/form/field/input/text.scss
new file mode 100644
index 0000000..c76bebd
--- /dev/null
+++ b/modules/web-console/frontend/app/modules/form/field/input/text.scss
@@ -0,0 +1,41 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+.checkbox label .input-tip {
+	position: initial;
+}
+
+.input-tip .fa-floppy-o {
+	position: absolute;
+    top: 0;
+    right: 0;
+    z-index: 2;
+
+    width: 34px;
+    height: 34px;
+
+    text-align: center;
+
+    display: inline-block;
+    line-height: 28px;
+    pointer-events: initial;
+}
+
+.input-tip .form-control-feedback {
+    height: auto;
+}
+

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/frontend/app/modules/form/field/label.directive.js
----------------------------------------------------------------------
diff --git a/modules/web-console/frontend/app/modules/form/field/label.directive.js b/modules/web-console/frontend/app/modules/form/field/label.directive.js
new file mode 100644
index 0000000..97ba598
--- /dev/null
+++ b/modules/web-console/frontend/app/modules/form/field/label.directive.js
@@ -0,0 +1,47 @@
+/*
+ * 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 ['igniteFormFieldLabel', [() => {
+    return {
+        restrict: 'E',
+        compile() {
+            return {
+                post($scope, $element, $attrs, [form, field], $transclude) {
+                    $transclude($scope, function(clone) {
+                        const text = clone.text();
+
+                        if (/(.*):$/.test(text))
+                            field.name = /(.*):$/.exec(text)[1];
+
+                        const $label = $element.parent().parent().find('.group-legend > label, .ignite-field > label');
+
+                        if ($label[0] && $element[0].id) {
+                            const id = $element[0].id;
+
+                            $label[0].id = id.indexOf('+') >= 0 ? $scope.$eval(id) : id;
+                        }
+
+                        $label.append(clone);
+                    });
+                }
+            };
+        },
+        replace: true,
+        transclude: true,
+        require: ['^form', '?^igniteFormField']
+    };
+}]];

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/frontend/app/modules/form/field/tooltip.directive.js
----------------------------------------------------------------------
diff --git a/modules/web-console/frontend/app/modules/form/field/tooltip.directive.js b/modules/web-console/frontend/app/modules/form/field/tooltip.directive.js
new file mode 100644
index 0000000..5005280
--- /dev/null
+++ b/modules/web-console/frontend/app/modules/form/field/tooltip.directive.js
@@ -0,0 +1,49 @@
+/*
+ * 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 template = '<i class="tipField fa fa-question-circle"></i>';
+
+export default ['igniteFormFieldTooltip', ['$tooltip', ($tooltip) => {
+    const link = ($scope, $element, $attrs, [form, field], $transclude) => {
+        const content = Array.prototype.slice
+            .apply($transclude($scope))
+            .reduce((html, el) => html += el.outerHTML || el.textContent || el, '');
+
+        $tooltip($element, { title: content });
+
+        if (field)
+            $element.attr('id', field.for + 'Tooltip');
+
+        // TODO cleanup css styles.
+        if ($element.hasClass('tipLabel'))
+            $element.removeClass('tipField');
+
+        if ($element.parent('label').length)
+            $element.addClass('tipLabel').removeClass('tipField');
+    };
+
+    return {
+        priority: 1,
+        restrict: 'E',
+        scope: {},
+        template,
+        link,
+        replace: true,
+        transclude: true,
+        require: ['^form', '?^igniteFormField']
+    };
+}]];

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/frontend/app/modules/form/field/up.directive.js
----------------------------------------------------------------------
diff --git a/modules/web-console/frontend/app/modules/form/field/up.directive.js b/modules/web-console/frontend/app/modules/form/field/up.directive.js
new file mode 100644
index 0000000..aba1cbe
--- /dev/null
+++ b/modules/web-console/frontend/app/modules/form/field/up.directive.js
@@ -0,0 +1,39 @@
+/*
+ * 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 ['igniteFormFieldUp', ['$tooltip', ($tooltip) => {
+    const controller = ['$element', function($element) {
+        $tooltip($element, { title: 'Move item up' });
+
+        this.up = () => {
+            const idx = this.models.indexOf(this.model);
+
+            this.models.splice(idx, 1);
+            this.models.splice(idx - 1, 0, this.model);
+        };
+    }];
+
+    return {
+        restrict: 'A',
+        bindToController: {
+            model: '=ngModel',
+            models: '=models'
+        },
+        controller,
+        controllerAs: '$ctrl'
+    };
+}]];

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/frontend/app/modules/form/form.module.js
----------------------------------------------------------------------
diff --git a/modules/web-console/frontend/app/modules/form/form.module.js b/modules/web-console/frontend/app/modules/form/form.module.js
new file mode 100644
index 0000000..23eafcd
--- /dev/null
+++ b/modules/web-console/frontend/app/modules/form/form.module.js
@@ -0,0 +1,96 @@
+/*
+ * 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';
+
+// Fields styles.
+import './field/field.scss';
+import './field/feedback.scss';
+import './field/input/text.scss';
+import './field/input/select.scss';
+
+// Panel.
+import igniteFormPanel from './panel/panel.directive';
+import igniteFormPanelField from './panel/field.directive';
+import igniteFormPanelChevron from './panel/chevron.directive';
+import igniteFormRevert from './panel/revert.directive';
+
+// Field.
+import igniteFormFieldLabel from './field/label.directive';
+import igniteFormFieldTooltip from './field/tooltip.directive';
+import placeholder from './field/bs-select-placeholder.directive';
+
+// Group.
+import igniteFormGroupAdd from './group/add.directive';
+import igniteFormGroupTooltip from './group/tooltip.directive';
+
+// Validators.
+import ipaddress from './validator/ipaddress.directive';
+import javaKeywords from './validator/java-keywords.directive';
+import javaPackageSpecified from './validator/java-package-specified.directive';
+import javaBuiltInClass from './validator/java-built-in-class.directive';
+import javaIdentifier from './validator/java-identifier.directive';
+import javaPackageName from './validator/java-package-name.directive';
+import propertyValueSpecified from './validator/property-value-specified.directive';
+import propertyUnique from './validator/property-unique.directive';
+import unique from './validator/unique.directive';
+import uuid from './validator/uuid.directive';
+
+// Helpers.
+import igniteFormFieldInputAutofocus from './field/input/autofocus.directive';
+import igniteFormControlFeedback from './field/form-control-feedback.directive';
+import igniteFormFieldUp from './field/up.directive';
+import igniteFormFieldDown from './field/down.directive';
+
+angular
+.module('ignite-console.Form', [
+
+])
+// Panel.
+.directive(...igniteFormPanel)
+.directive(...igniteFormPanelField)
+.directive(...igniteFormPanelChevron)
+.directive(...igniteFormRevert)
+// Field.
+.directive(...igniteFormFieldLabel)
+.directive(...igniteFormFieldTooltip)
+.directive(...placeholder)
+// Group.
+.directive(...igniteFormGroupAdd)
+.directive(...igniteFormGroupTooltip)
+// Validators.
+.directive(...ipaddress)
+.directive(...javaKeywords)
+.directive(...javaPackageSpecified)
+.directive(...javaBuiltInClass)
+.directive(...javaIdentifier)
+.directive(...javaPackageName)
+.directive(...propertyValueSpecified)
+.directive(...propertyUnique)
+.directive(...unique)
+.directive(...uuid)
+// Helpers.
+.directive(...igniteFormFieldInputAutofocus)
+.directive(...igniteFormControlFeedback)
+.directive(...igniteFormFieldUp)
+.directive(...igniteFormFieldDown)
+// Generator of globally unique identifier.
+.factory('IgniteFormGUID', [() => {
+    let guid = 0;
+
+    return () => `form-field-${guid++}`;
+}]);

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/frontend/app/modules/form/group/add.directive.js
----------------------------------------------------------------------
diff --git a/modules/web-console/frontend/app/modules/form/group/add.directive.js b/modules/web-console/frontend/app/modules/form/group/add.directive.js
new file mode 100644
index 0000000..7e9a50c
--- /dev/null
+++ b/modules/web-console/frontend/app/modules/form/group/add.directive.js
@@ -0,0 +1,40 @@
+/*
+ * 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 template = '<i class="group-legend-btn fa fa-plus"></i>';
+
+export default ['igniteFormGroupAdd', ['$tooltip', ($tooltip) => {
+    const link = ($scope, $element, $attrs, $ctrls, $transclude) => {
+        const content = Array.prototype.slice
+            .apply($transclude($scope))
+            .reduce((html, el) => html += el.outerHTML || el.textContent || el, '');
+
+        $tooltip($element, { title: content });
+
+        $element.closest('.group').find('.group-legend').append($element);
+    };
+
+    return {
+        restrict: 'E',
+        scope: {},
+        template,
+        link,
+        replace: true,
+        transclude: true,
+        require: ['^form']
+    };
+}]];

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/frontend/app/modules/form/group/tooltip.directive.js
----------------------------------------------------------------------
diff --git a/modules/web-console/frontend/app/modules/form/group/tooltip.directive.js b/modules/web-console/frontend/app/modules/form/group/tooltip.directive.js
new file mode 100644
index 0000000..3e470e1
--- /dev/null
+++ b/modules/web-console/frontend/app/modules/form/group/tooltip.directive.js
@@ -0,0 +1,40 @@
+/*
+ * 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 template = '<i class="group-legend-btn fa fa-question-circle"></i>';
+
+export default ['igniteFormGroupTooltip', ['$tooltip', ($tooltip) => {
+    const link = ($scope, $element, $attrs, $ctrls, $transclude) => {
+        const content = Array.prototype.slice
+            .apply($transclude($scope))
+            .reduce((html, el) => html += el.outerHTML || el.textContent || el, '');
+
+        $tooltip($element, { title: content });
+
+        $element.closest('.group').find('.group-legend').append($element);
+    };
+
+    return {
+        restrict: 'E',
+        scope: {},
+        template,
+        link,
+        replace: true,
+        transclude: true,
+        require: ['^form']
+    };
+}]];

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/frontend/app/modules/form/panel/chevron.directive.js
----------------------------------------------------------------------
diff --git a/modules/web-console/frontend/app/modules/form/panel/chevron.directive.js b/modules/web-console/frontend/app/modules/form/panel/chevron.directive.js
new file mode 100644
index 0000000..6af560b
--- /dev/null
+++ b/modules/web-console/frontend/app/modules/form/panel/chevron.directive.js
@@ -0,0 +1,53 @@
+/*
+ * 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 template = `<i class='fa' ng-class='isOpen ? "fa-chevron-circle-down" : "fa-chevron-circle-right"'></i>`; // eslint-disable-line quotes
+
+export default ['igniteFormPanelChevron', [() => {
+    const controller = [() => {}];
+
+    const link = ($scope, $element, $attrs, [bsCollapseCtrl]) => {
+        const $target = $element.parent().parent().find('.panel-collapse');
+
+        bsCollapseCtrl.$viewChangeListeners.push(function() {
+            const index = bsCollapseCtrl.$targets.reduce((acc, el, i) => {
+                if (el[0] === $target[0])
+                    acc.push(i);
+
+                return acc;
+            }, [])[0];
+
+            $scope.isOpen = false;
+
+            const active = bsCollapseCtrl.$activeIndexes();
+
+            if ((active instanceof Array) && active.indexOf(index) !== -1 || active === index)
+                $scope.isOpen = true;
+        });
+    };
+
+    return {
+        restrict: 'E',
+        scope: {},
+        link,
+        template,
+        controller,
+        replace: true,
+        transclude: true,
+        require: ['^bsCollapse']
+    };
+}]];

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/frontend/app/modules/form/panel/field.directive.js
----------------------------------------------------------------------
diff --git a/modules/web-console/frontend/app/modules/form/panel/field.directive.js b/modules/web-console/frontend/app/modules/form/panel/field.directive.js
new file mode 100644
index 0000000..5dc7b07
--- /dev/null
+++ b/modules/web-console/frontend/app/modules/form/panel/field.directive.js
@@ -0,0 +1,69 @@
+/*
+ * 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 ['igniteFormPanelField', ['$parse', 'IgniteLegacyTable', ($parse, LegacyTable) => {
+    const link = (scope, element, attrs, [ngModelCtrl, formCtrl]) => {
+        formCtrl.$defaults = formCtrl.$defaults || {};
+
+        const { name, ngModel } = attrs;
+        const getter = () => $parse(ngModel)(scope);
+
+        const saveDefault = () => {
+            formCtrl.$defaults[name] = _.cloneDeep(getter());
+        };
+
+        const resetDefault = () => {
+            ngModelCtrl.$viewValue = formCtrl.$defaults[name];
+
+            ngModelCtrl.$valid = true;
+            ngModelCtrl.$invalid = false;
+            ngModelCtrl.$error = {};
+            ngModelCtrl.$render();
+        };
+
+        if (!(_.isNull(formCtrl.$defaults[name]) || _.isUndefined(formCtrl.$defaults[name])))
+            resetDefault();
+        else
+            saveDefault();
+
+        scope.tableReset = () => {
+            if (!LegacyTable.tableSaveAndReset())
+                LegacyTable.tableReset();
+        };
+
+        scope.$watch(() => formCtrl.$pristine, () => {
+            if (!formCtrl.$pristine)
+                return;
+
+            saveDefault();
+            resetDefault();
+        });
+
+        scope.$watch(() => ngModelCtrl.$modelValue, () => {
+            if (!formCtrl.$pristine)
+                return;
+
+            saveDefault();
+        });
+    };
+
+    return {
+        restrict: 'A',
+        link,
+        require: ['ngModel', '^form']
+    };
+}]];

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/frontend/app/modules/form/panel/panel.directive.js
----------------------------------------------------------------------
diff --git a/modules/web-console/frontend/app/modules/form/panel/panel.directive.js b/modules/web-console/frontend/app/modules/form/panel/panel.directive.js
new file mode 100644
index 0000000..b8e7c25
--- /dev/null
+++ b/modules/web-console/frontend/app/modules/form/panel/panel.directive.js
@@ -0,0 +1,37 @@
+/*
+ * 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 ['form', [() => {
+    const link = (scope, $element, $attrs, [form]) => {
+        const $form = $element.parent().closest('form');
+
+        scope.$watch(() => {
+            return $form.hasClass('ng-pristine');
+        }, (value) => {
+            if (!value)
+                return;
+
+            form.$setPristine();
+        });
+    };
+
+    return {
+        restrict: 'E',
+        link,
+        require: ['^form']
+    };
+}]];

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/frontend/app/modules/form/panel/revert.directive.js
----------------------------------------------------------------------
diff --git a/modules/web-console/frontend/app/modules/form/panel/revert.directive.js b/modules/web-console/frontend/app/modules/form/panel/revert.directive.js
new file mode 100644
index 0000000..2076b0d
--- /dev/null
+++ b/modules/web-console/frontend/app/modules/form/panel/revert.directive.js
@@ -0,0 +1,54 @@
+/*
+ * 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 template = '<i ng-show="form.$dirty" class="fa fa-undo pull-right" ng-click="revert($event)"></i>';
+
+export default ['igniteFormRevert', ['$tooltip', 'IgniteLegacyTable', ($tooltip, LegacyTable) => {
+    const link = (scope, $element, $attrs, [form]) => {
+        $tooltip($element, { title: 'Undo unsaved changes' });
+
+        scope.form = form;
+
+        scope.revert = (e) => {
+            e.stopPropagation();
+
+            LegacyTable.tableReset();
+
+            _.forOwn(form.$defaults, (value, name) => {
+                const field = form[name];
+
+                if (field) {
+                    field.$viewValue = value;
+                    field.$setViewValue(value);
+                    field.$setPristine();
+                    field.$render();
+                }
+            });
+
+            form.$setPristine();
+        };
+    };
+
+    return {
+        restrict: 'E',
+        scope: { },
+        template,
+        link,
+        replace: true,
+        require: ['^form']
+    };
+}]];

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/frontend/app/modules/form/validator/ipaddress.directive.js
----------------------------------------------------------------------
diff --git a/modules/web-console/frontend/app/modules/form/validator/ipaddress.directive.js b/modules/web-console/frontend/app/modules/form/validator/ipaddress.directive.js
new file mode 100644
index 0000000..77e63f6
--- /dev/null
+++ b/modules/web-console/frontend/app/modules/form/validator/ipaddress.directive.js
@@ -0,0 +1,86 @@
+/*
+ * 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 ['ipaddress', ['IgniteInetAddress', (InetAddress) => {
+    const onlyDigits = (str) => (/^\d+$/.test(str));
+
+    const strictParseInt = (str) => onlyDigits(str) ? parseInt(str, 10) : Number.NaN;
+
+    const parse = (commonIpAddress) => {
+        const [ipOrHost, portRange] = commonIpAddress.split(':');
+        const ports = _.isUndefined(portRange) ? [] : portRange.split('..').map(strictParseInt);
+
+        return {ipOrHost, ports};
+    };
+
+    const link = (scope, el, attrs, [ngModel]) => {
+        const isEmpty = (modelValue) => {
+            return ngModel.$isEmpty(modelValue) || _.isUndefined(attrs.ipaddress) || attrs.ipaddress !== 'true';
+        };
+
+        const portRange = !_.isNil(attrs.ipaddressWithPortRange);
+
+        if (attrs.ipaddressWithPort) {
+            ngModel.$validators.ipaddressPort = (modelValue) => {
+                if (isEmpty(modelValue) || modelValue.indexOf(':') === -1)
+                    return true;
+
+                if ((modelValue.match(/:/g) || []).length > 1)
+                    return false;
+
+                const {ports} = parse(modelValue);
+
+                if (ports.length !== 1)
+                    return portRange;
+
+                return InetAddress.validPort(ports[0]);
+            };
+        }
+
+        if (portRange) {
+            ngModel.$validators.ipaddressPortRange = (modelValue) => {
+                if (isEmpty(modelValue) || modelValue.indexOf('..') === -1)
+                    return true;
+
+                const {ports} = parse(modelValue);
+
+                if (ports.length !== 2)
+                    return false;
+
+                return InetAddress.validPort(ports[0]) && InetAddress.validPort(ports[1]) && ports[0] < ports[1];
+            };
+        }
+
+        ngModel.$validators.ipaddress = (modelValue) => {
+            if (isEmpty(modelValue))
+                return true;
+
+            const {ipOrHost, ports} = parse(modelValue);
+
+            if (attrs.ipaddressWithPort || attrs.ipaddressWithPortRange || ports.length === 0)
+                return InetAddress.validHost(ipOrHost);
+
+            return false;
+        };
+    };
+
+    return {
+        restrict: 'A',
+        link,
+        require: ['ngModel']
+    };
+}]];

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/frontend/app/modules/form/validator/java-built-in-class.directive.js
----------------------------------------------------------------------
diff --git a/modules/web-console/frontend/app/modules/form/validator/java-built-in-class.directive.js b/modules/web-console/frontend/app/modules/form/validator/java-built-in-class.directive.js
new file mode 100644
index 0000000..1a4b504
--- /dev/null
+++ b/modules/web-console/frontend/app/modules/form/validator/java-built-in-class.directive.js
@@ -0,0 +1,31 @@
+/*
+ * 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 ['javaBuiltInClass', ['JavaTypes', (JavaTypes) => {
+    const link = (scope, el, attrs, [ngModel]) => {
+        if (_.isUndefined(attrs.javaBuiltInClass) || !attrs.javaBuiltInClass)
+            return;
+
+        ngModel.$validators.javaBuiltInClass = (value) => JavaTypes.nonBuiltInClass(value);
+    };
+
+    return {
+        restrict: 'A',
+        link,
+        require: ['ngModel']
+    };
+}]];

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/frontend/app/modules/form/validator/java-identifier.directive.js
----------------------------------------------------------------------
diff --git a/modules/web-console/frontend/app/modules/form/validator/java-identifier.directive.js b/modules/web-console/frontend/app/modules/form/validator/java-identifier.directive.js
new file mode 100644
index 0000000..5cbf7fb
--- /dev/null
+++ b/modules/web-console/frontend/app/modules/form/validator/java-identifier.directive.js
@@ -0,0 +1,31 @@
+/*
+ * 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 ['javaIdentifier', ['JavaTypes', (JavaTypes) => {
+    const link = (scope, el, attrs, [ngModel]) => {
+        if (_.isUndefined(attrs.javaIdentifier) || !attrs.javaIdentifier)
+            return;
+
+        ngModel.$validators.javaIdentifier = (value) => JavaTypes.validIdentifier(value);
+    };
+
+    return {
+        restrict: 'A',
+        link,
+        require: ['ngModel']
+    };
+}]];

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/frontend/app/modules/form/validator/java-keywords.directive.js
----------------------------------------------------------------------
diff --git a/modules/web-console/frontend/app/modules/form/validator/java-keywords.directive.js b/modules/web-console/frontend/app/modules/form/validator/java-keywords.directive.js
new file mode 100644
index 0000000..d97e59a
--- /dev/null
+++ b/modules/web-console/frontend/app/modules/form/validator/java-keywords.directive.js
@@ -0,0 +1,42 @@
+/*
+ * 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 ['javaKeywords', ['JavaTypes', (JavaTypes) => {
+    const link = (scope, el, attrs, [ngModel]) => {
+        if (_.isUndefined(attrs.javaKeywords) || !attrs.javaKeywords)
+            return;
+
+        const packageOnly = attrs.javaPackageName === 'package-only';
+
+        ngModel.$validators.javaKeywords = (value) => {
+            if (value) {
+                if (!JavaTypes.validIdentifier(value) || (!packageOnly && !JavaTypes.packageSpecified(value)))
+                    return true;
+
+                return _.findIndex(value.split('.'), JavaTypes.isKeywords) < 0;
+            }
+
+            return true;
+        };
+    };
+
+    return {
+        restrict: 'A',
+        link,
+        require: ['ngModel']
+    };
+}]];

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/frontend/app/modules/form/validator/java-package-name.directive.js
----------------------------------------------------------------------
diff --git a/modules/web-console/frontend/app/modules/form/validator/java-package-name.directive.js b/modules/web-console/frontend/app/modules/form/validator/java-package-name.directive.js
new file mode 100644
index 0000000..ac38179
--- /dev/null
+++ b/modules/web-console/frontend/app/modules/form/validator/java-package-name.directive.js
@@ -0,0 +1,31 @@
+/*
+ * 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 ['javaPackageName', ['JavaTypes', (JavaTypes) => {
+    const link = (scope, el, attrs, [ngModel]) => {
+        if (_.isUndefined(attrs.javaPackageName) || !attrs.javaPackageName)
+            return;
+
+        ngModel.$validators.javaPackageName = (value) => JavaTypes.validPackage(value);
+    };
+
+    return {
+        restrict: 'A',
+        link,
+        require: ['ngModel']
+    };
+}]];

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/frontend/app/modules/form/validator/java-package-specified.directive.js
----------------------------------------------------------------------
diff --git a/modules/web-console/frontend/app/modules/form/validator/java-package-specified.directive.js b/modules/web-console/frontend/app/modules/form/validator/java-package-specified.directive.js
new file mode 100644
index 0000000..451d7ec
--- /dev/null
+++ b/modules/web-console/frontend/app/modules/form/validator/java-package-specified.directive.js
@@ -0,0 +1,34 @@
+/*
+ * 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 ['javaPackageSpecified', ['JavaTypes', (JavaTypes) => {
+    const link = (scope, el, attrs, [ngModel]) => {
+        if (_.isUndefined(attrs.javaPackageSpecified))
+            return;
+
+        const allowBuiltIn = attrs.javaPackageSpecified === 'allow-built-in';
+
+        ngModel.$validators.javaPackageSpecified = (value) => !value || !JavaTypes.validIdentifier(value) || JavaTypes.packageSpecified(value) ||
+                (allowBuiltIn && !JavaTypes.nonBuiltInClass(value));
+    };
+
+    return {
+        restrict: 'A',
+        link,
+        require: ['ngModel']
+    };
+}]];

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/frontend/app/modules/form/validator/property-unique.directive.js
----------------------------------------------------------------------
diff --git a/modules/web-console/frontend/app/modules/form/validator/property-unique.directive.js b/modules/web-console/frontend/app/modules/form/validator/property-unique.directive.js
new file mode 100644
index 0000000..8cfae89
--- /dev/null
+++ b/modules/web-console/frontend/app/modules/form/validator/property-unique.directive.js
@@ -0,0 +1,47 @@
+/*
+ * 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 ['ignitePropertyUnique', ['$parse', ($parse) => {
+    const link = (scope, el, attrs, [ngModel]) => {
+        if (_.isUndefined(attrs.ignitePropertyUnique) || !attrs.ignitePropertyUnique)
+            return;
+
+        ngModel.$validators.ignitePropertyUnique = (value) => {
+            const arr = $parse(attrs.ignitePropertyUnique)(scope);
+
+            // Return true in case if array not exist, array empty.
+            if (!value || !arr || !arr.length)
+                return true;
+
+            const key = value.split('=')[0];
+            const idx = _.findIndex(arr, (item) => item.split('=')[0] === key);
+
+            // In case of new element check all items.
+            if (attrs.name === 'new')
+                return idx < 0;
+
+            // Check for $index in case of editing in-place.
+            return (_.isNumber(scope.$index) && (idx < 0 || scope.$index === idx));
+        };
+    };
+
+    return {
+        restrict: 'A',
+        link,
+        require: ['ngModel']
+    };
+}]];

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/frontend/app/modules/form/validator/property-value-specified.directive.js
----------------------------------------------------------------------
diff --git a/modules/web-console/frontend/app/modules/form/validator/property-value-specified.directive.js b/modules/web-console/frontend/app/modules/form/validator/property-value-specified.directive.js
new file mode 100644
index 0000000..d113a4f
--- /dev/null
+++ b/modules/web-console/frontend/app/modules/form/validator/property-value-specified.directive.js
@@ -0,0 +1,31 @@
+/*
+ * 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 ['ignitePropertyValueSpecified', [() => {
+    const link = (scope, el, attrs, [ngModel]) => {
+        if (_.isUndefined(attrs.ignitePropertyValueSpecified) || !attrs.ignitePropertyValueSpecified)
+            return;
+
+        ngModel.$validators.ignitePropertyValueSpecified = (value) => value ? value.indexOf('=') > 0 : true;
+    };
+
+    return {
+        restrict: 'A',
+        link,
+        require: ['ngModel']
+    };
+}]];

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/frontend/app/modules/form/validator/unique.directive.js
----------------------------------------------------------------------
diff --git a/modules/web-console/frontend/app/modules/form/validator/unique.directive.js b/modules/web-console/frontend/app/modules/form/validator/unique.directive.js
new file mode 100644
index 0000000..0e6af18
--- /dev/null
+++ b/modules/web-console/frontend/app/modules/form/validator/unique.directive.js
@@ -0,0 +1,49 @@
+/*
+ * 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 ['igniteUnique', ['$parse', ($parse) => {
+    const link = (scope, el, attrs, [ngModel]) => {
+        if (_.isUndefined(attrs.igniteUnique) || !attrs.igniteUnique)
+            return;
+
+        const isNew = _.startsWith(attrs.name, 'new');
+        const property = attrs.igniteUniqueProperty;
+
+        ngModel.$validators.igniteUnique = (value) => {
+            const arr = $parse(attrs.igniteUnique)(scope);
+
+            // Return true in case if array not exist, array empty.
+            if (!arr || !arr.length)
+                return true;
+
+            const idx = _.findIndex(arr, (item) => (property ? item[property] : item) === value);
+
+            // In case of new element check all items.
+            if (isNew)
+                return idx < 0;
+
+            // Check for $index in case of editing in-place.
+            return (_.isNumber(scope.$index) && (idx < 0 || scope.$index === idx));
+        };
+    };
+
+    return {
+        restrict: 'A',
+        link,
+        require: ['ngModel']
+    };
+}]];

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/frontend/app/modules/form/validator/uuid.directive.js
----------------------------------------------------------------------
diff --git a/modules/web-console/frontend/app/modules/form/validator/uuid.directive.js b/modules/web-console/frontend/app/modules/form/validator/uuid.directive.js
new file mode 100644
index 0000000..0704175
--- /dev/null
+++ b/modules/web-console/frontend/app/modules/form/validator/uuid.directive.js
@@ -0,0 +1,37 @@
+/*
+ * 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 ['uuid', ['JavaTypes', (JavaTypes) => {
+    const link = (scope, el, attrs, [ngModel]) => {
+        const isEmpty = (modelValue) => {
+            return ngModel.$isEmpty(modelValue) || _.isUndefined(attrs.uuid) || attrs.uuid !== 'true';
+        };
+
+        ngModel.$validators.uuid = (modelValue) => {
+            if (isEmpty(modelValue))
+                return true;
+
+            return JavaTypes.validUUID(modelValue);
+        };
+    };
+
+    return {
+        restrict: 'A',
+        link,
+        require: ['ngModel']
+    };
+}]];

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/frontend/app/modules/getting-started/GettingStarted.provider.js
----------------------------------------------------------------------
diff --git a/modules/web-console/frontend/app/modules/getting-started/GettingStarted.provider.js b/modules/web-console/frontend/app/modules/getting-started/GettingStarted.provider.js
new file mode 100644
index 0000000..cf9f561
--- /dev/null
+++ b/modules/web-console/frontend/app/modules/getting-started/GettingStarted.provider.js
@@ -0,0 +1,112 @@
+/*
+ * 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';
+
+// Getting started pages.
+import PAGES from 'app/data/getting-started.json';
+
+angular
+    .module('ignite-console.getting-started', [])
+    .provider('igniteGettingStarted', function() {
+        const items = PAGES;
+
+        this.push = (before, data) => {
+            const idx = _.findIndex(items, {title: before});
+
+            if (idx < 0)
+                items.push(data);
+            else
+                items.splice(idx, 0, data);
+        };
+
+        this.update = (before, data) => {
+            const idx = _.findIndex(items, {title: before});
+
+            if (idx >= 0)
+                items[idx] = data;
+        };
+
+        this.$get = [function() {
+            return items;
+        }];
+    })
+    .service('gettingStarted', ['$rootScope', '$modal', 'igniteGettingStarted', function($root, $modal, igniteGettingStarted) {
+        const _model = igniteGettingStarted;
+
+        let _page = 0;
+
+        const scope = $root.$new();
+
+        scope.ui = {
+            showGettingStarted: false
+        };
+
+        function _fillPage() {
+            scope.title = _model[_page].title;
+            scope.message = _model[_page].message.join(' ');
+        }
+
+        scope.isFirst = () => _page === 0;
+
+        scope.isLast = () => _page === _model.length - 1;
+
+        scope.next = () => {
+            _page += 1;
+
+            _fillPage();
+        };
+
+        scope.prev = () => {
+            _page -= 1;
+
+            _fillPage();
+        };
+
+        const dialog = $modal({templateUrl: '/templates/getting-started.html', scope, placement: 'center', show: false, backdrop: 'static'});
+
+        scope.close = () => {
+            try {
+                localStorage.showGettingStarted = scope.ui.showGettingStarted;
+            }
+            catch (ignore) {
+                // No-op.
+            }
+
+            dialog.hide();
+        };
+
+        return {
+            tryShow: (force) => {
+                try {
+                    scope.ui.showGettingStarted = _.isNil(localStorage.showGettingStarted)
+                        || localStorage.showGettingStarted === 'true';
+                }
+                catch (ignore) {
+                    // No-op.
+                }
+
+                if (force || scope.ui.showGettingStarted) {
+                    _page = 0;
+
+                    _fillPage();
+
+                    dialog.$promise.then(dialog.show);
+                }
+            }
+        };
+    }]);


[09/52] ignite git commit: Web Console beta-3.

Posted by ak...@apache.org.
http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/src/main/js/generator/generator-java.js
----------------------------------------------------------------------
diff --git a/modules/web-console/src/main/js/generator/generator-java.js b/modules/web-console/src/main/js/generator/generator-java.js
deleted file mode 100644
index d9425e0..0000000
--- a/modules/web-console/src/main/js/generator/generator-java.js
+++ /dev/null
@@ -1,3404 +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.
- */
-
-// Java generation entry point.
-const $generatorJava = {};
-
-/**
- * Translate some value to valid java code.
- *
- * @param val Value to convert.
- * @param type Value type.
- * @returns {*} String with value that will be valid for java.
- */
-$generatorJava.toJavaCode = function(val, type) {
-    if (val === null)
-        return 'null';
-
-    if (type === 'raw')
-        return val;
-
-    if (type === 'class')
-        return val + '.class';
-
-    if (type === 'float')
-        return val + 'f';
-
-    if (type === 'path')
-        return '"' + val.replace(/\\/g, '\\\\') + '"';
-
-    if (type)
-        return type + '.' + val;
-
-    if (typeof (val) === 'string')
-        return '"' + val.replace('"', '\\"') + '"';
-
-    if (typeof (val) === 'number' || typeof (val) === 'boolean')
-        return String(val);
-
-    return 'Unknown type: ' + typeof (val) + ' (' + val + ')';
-};
-
-/**
- * @param propName Property name.
- * @param setterName Optional concrete setter name.
- * @returns Property setter with name by java conventions.
- */
-$generatorJava.setterName = function(propName, setterName) {
-    return setterName ? setterName : $generatorCommon.toJavaName('set', propName);
-};
-
-// Add constructor argument
-$generatorJava.constructorArg = function(obj, propName, dflt, notFirst, opt) {
-    const v = (obj ? obj[propName] : null) || dflt;
-
-    if ($generatorCommon.isDefinedAndNotEmpty(v))
-        return (notFirst ? ', ' : '') + $generatorJava.toJavaCode(v);
-    else if (!opt)
-        return notFirst ? ', null' : 'null';
-
-    return '';
-};
-
-/**
- * Add variable declaration.
- *
- * @param res Resulting output with generated code.
- * @param varName Variable name.
- * @param varFullType Variable full class name to be added to imports.
- * @param varFullActualType Variable actual full class name to be added to imports.
- * @param varFullGenericType1 Optional full class name of first generic.
- * @param varFullGenericType2 Optional full class name of second generic.
- * @param subClass If 'true' then variable will be declared as anonymous subclass.
- */
-$generatorJava.declareVariable = function(res, varName, varFullType, varFullActualType, varFullGenericType1, varFullGenericType2, subClass) {
-    res.emptyLineIfNeeded();
-
-    const varType = res.importClass(varFullType);
-
-    const varNew = !res.vars[varName];
-
-    if (varNew)
-        res.vars[varName] = true;
-
-    if (varFullActualType && varFullGenericType1) {
-        const varActualType = res.importClass(varFullActualType);
-        const varGenericType1 = res.importClass(varFullGenericType1);
-        let varGenericType2 = null;
-
-        if (varFullGenericType2)
-            varGenericType2 = res.importClass(varFullGenericType2);
-
-        res.line((varNew ? (varType + '<' + varGenericType1 + (varGenericType2 ? ', ' + varGenericType2 : '') + '> ') : '') +
-            varName + ' = new ' + varActualType + '<>();');
-    }
-    else
-        res.line((varNew ? (varType + ' ') : '') + varName + ' = new ' + varType + '()' + (subClass ? ' {' : ';'));
-
-    if (!subClass)
-        res.needEmptyLine = true;
-
-    return varName;
-};
-
-/**
- * Add local variable declaration.
- *
- * @param res Resulting output with generated code.
- * @param varName Variable name.
- * @param varFullType Variable full class name to be added to imports.
- */
-$generatorJava.declareVariableLocal = function(res, varName, varFullType) {
-    const varType = res.importClass(varFullType);
-
-    res.line(varType + ' ' + varName + ' = new ' + varType + '();');
-
-    res.needEmptyLine = true;
-};
-
-/**
- * Add custom variable declaration.
- *
- * @param res Resulting output with generated code.
- * @param varName Variable name.
- * @param varFullType Variable full class name to be added to imports.
- * @param varExpr Custom variable creation expression.
- * @param modifier Additional variable modifier.
- */
-$generatorJava.declareVariableCustom = function(res, varName, varFullType, varExpr, modifier) {
-    const varType = res.importClass(varFullType);
-
-    const varNew = !res.vars[varName];
-
-    if (varNew)
-        res.vars[varName] = true;
-
-    res.line((varNew ? ((modifier ? modifier + ' ' : '') + varType + ' ') : '') + varName + ' = ' + varExpr + ';');
-
-    res.needEmptyLine = true;
-};
-
-/**
- * Add array variable declaration.
- *
- * @param res Resulting output with generated code.
- * @param varName Variable name.
- * @param varFullType Variable full class name to be added to imports.
- * @param length Array length.
- */
-$generatorJava.declareVariableArray = function(res, varName, varFullType, length) {
-    const varType = res.importClass(varFullType);
-
-    const varNew = !res.vars[varName];
-
-    if (varNew)
-        res.vars[varName] = true;
-
-    res.line((varNew ? (varType + '[] ') : '') + varName + ' = new ' + varType + '[' + length + '];');
-
-    res.needEmptyLine = true;
-};
-
-/**
- * Clear list of declared variables.
- *
- * @param res
- */
-$generatorJava.resetVariables = function(res) {
-    res.vars = {};
-};
-
-/**
- * Add property via setter / property name.
- *
- * @param res Resulting output with generated code.
- * @param varName Variable name.
- * @param obj Source object with data.
- * @param propName Property name to take from source object.
- * @param dataType Optional info about property data type.
- * @param setterName Optional special setter name.
- * @param dflt Optional default value.
- */
-$generatorJava.property = function(res, varName, obj, propName, dataType, setterName, dflt) {
-    if (!_.isNil(obj)) {
-        const val = obj[propName];
-
-        if ($generatorCommon.isDefinedAndNotEmpty(val)) {
-            const missDflt = _.isNil(dflt);
-
-            // Add to result if no default provided or value not equals to default.
-            if (missDflt || (!missDflt && val !== dflt)) {
-                res.line(varName + '.' + $generatorJava.setterName(propName, setterName) +
-                    '(' + $generatorJava.toJavaCode(val, dataType) + ');');
-
-                return true;
-            }
-        }
-    }
-
-    return false;
-};
-
-/**
- * Add enum property via setter / property name.
- *
- * @param res Resulting output with generated code.
- * @param varName Variable name.
- * @param obj Source object with data.
- * @param propName Property name to take from source object.
- * @param dataType Name of enum class
- * @param setterName Optional special setter name.
- * @param dflt Optional default value.
- */
-$generatorJava.enumProperty = function(res, varName, obj, propName, dataType, setterName, dflt) {
-    const val = obj[propName];
-
-    if ($generatorCommon.isDefinedAndNotEmpty(val)) {
-        const missDflt = _.isNil(dflt);
-
-        // Add to result if no default provided or value not equals to default.
-        if (missDflt || (!missDflt && val !== dflt)) {
-            res.line(varName + '.' + $generatorJava.setterName(propName, setterName) +
-                '(' + $generatorJava.toJavaCode(val, dataType ? res.importClass(dataType) : null) + ');');
-
-            return true;
-        }
-    }
-
-    return false;
-};
-
-// Add property for class name.
-$generatorJava.classNameProperty = function(res, varName, obj, propName) {
-    const val = obj[propName];
-
-    if (!_.isNil(val)) {
-        res.line(varName + '.' + $generatorJava.setterName(propName) +
-            '("' + $generatorCommon.JavaTypes.fullClassName(val) + '");');
-    }
-};
-
-/**
- * Add list property.
- *
- * @param res Resulting output with generated code.
- * @param varName Variable name.
- * @param obj Source object with data.
- * @param propName Property name to take from source object.
- * @param dataType Optional data type.
- * @param setterName Optional setter name.
- */
-$generatorJava.listProperty = function(res, varName, obj, propName, dataType, setterName) {
-    const val = obj[propName];
-
-    if (val && val.length > 0) {
-        res.emptyLineIfNeeded();
-
-        res.importClass('java.util.Arrays');
-
-        $generatorJava.fxVarArgs(res, varName + '.' + $generatorJava.setterName(propName, setterName), false,
-            _.map(val, (v) => $generatorJava.toJavaCode(v, dataType)), '(Arrays.asList(', '))');
-
-        res.needEmptyLine = true;
-    }
-};
-
-/**
- * Add function with varargs arguments.
- *
- * @param res Resulting output with generated code.
- * @param fx Function name.
- * @param quote Whether to quote arguments.
- * @param args Array with arguments.
- * @param startBlock Optional start block string.
- * @param endBlock Optional end block string.
- */
-$generatorJava.fxVarArgs = function(res, fx, quote, args, startBlock = '(', endBlock = ')') {
-    const quoteArg = (arg) => quote ? '"' + arg + '"' : arg;
-
-    if (args.length === 1)
-        res.append(fx + startBlock + quoteArg(args[0]) + endBlock + ';');
-    else {
-        res.startBlock(fx + startBlock);
-
-        const len = args.length - 1;
-
-        _.forEach(args, (arg, ix) => res.line(quoteArg(arg) + (ix < len ? ', ' : '')));
-
-        res.endBlock(endBlock + ';');
-    }
-};
-
-/**
- * Add array property.
- *
- * @param res Resulting output with generated code.
- * @param varName Variable name.
- * @param obj Source object with data.
- * @param propName Property name to take from source object.
- * @param setterName Optional setter name.
- */
-$generatorJava.arrayProperty = function(res, varName, obj, propName, setterName) {
-    const val = obj[propName];
-
-    if (val && val.length > 0) {
-        res.emptyLineIfNeeded();
-
-        $generatorJava.fxVarArgs(res, varName + '.' + $generatorJava.setterName(propName, setterName), false,
-            _.map(val, (v) => 'new ' + res.importClass(v) + '()'), '({ ', ' });');
-
-        res.needEmptyLine = true;
-    }
-};
-
-/**
- * Add multi-param property (setter with several arguments).
- *
- * @param res Resulting output with generated code.
- * @param varName Variable name.
- * @param obj Source object with data.
- * @param propName Property name to take from source object.
- * @param dataType Optional data type.
- * @param setterName Optional setter name.
- */
-$generatorJava.multiparamProperty = function(res, varName, obj, propName, dataType, setterName) {
-    const val = obj[propName];
-
-    if (val && val.length > 0) {
-        $generatorJava.fxVarArgs(res, varName + '.' + $generatorJava.setterName(propName, setterName), false,
-            _.map(val, (v) => $generatorJava.toJavaCode(dataType === 'class' ? res.importClass(v) : v, dataType)));
-    }
-};
-
-/**
- * Add complex bean.
- *
- * @param res Resulting output with generated code.
- * @param varName Variable name.
- * @param bean
- * @param beanPropName Bean property name.
- * @param beanVarName
- * @param beanClass Bean class.
- * @param props
- * @param createBeanAlthoughNoProps If 'true' then create empty bean.
- */
-$generatorJava.beanProperty = function(res, varName, bean, beanPropName, beanVarName, beanClass, props, createBeanAlthoughNoProps) {
-    if (bean && $generatorCommon.hasProperty(bean, props)) {
-        res.emptyLineIfNeeded();
-
-        $generatorJava.declareVariable(res, beanVarName, beanClass);
-
-        _.forIn(props, function(descr, propName) {
-            if (props.hasOwnProperty(propName)) {
-                if (descr) {
-                    switch (descr.type) {
-                        case 'list':
-                            $generatorJava.listProperty(res, beanVarName, bean, propName, descr.elementsType, descr.setterName);
-                            break;
-
-                        case 'array':
-                            $generatorJava.arrayProperty(res, beanVarName, bean, propName, descr.setterName);
-                            break;
-
-                        case 'enum':
-                            $generatorJava.enumProperty(res, beanVarName, bean, propName, descr.enumClass, descr.setterName, descr.dflt);
-                            break;
-
-                        case 'float':
-                            $generatorJava.property(res, beanVarName, bean, propName, 'float', descr.setterName);
-                            break;
-
-                        case 'path':
-                            $generatorJava.property(res, beanVarName, bean, propName, 'path', descr.setterName);
-                            break;
-
-                        case 'raw':
-                            $generatorJava.property(res, beanVarName, bean, propName, 'raw', descr.setterName);
-                            break;
-
-                        case 'propertiesAsList':
-                            const val = bean[propName];
-
-                            if (val && val.length > 0) {
-                                $generatorJava.declareVariable(res, descr.propVarName, 'java.util.Properties');
-
-                                _.forEach(val, function(nameAndValue) {
-                                    const eqIndex = nameAndValue.indexOf('=');
-
-                                    if (eqIndex >= 0) {
-                                        res.line(descr.propVarName + '.setProperty(' +
-                                            '"' + nameAndValue.substring(0, eqIndex) + '", ' +
-                                            '"' + nameAndValue.substr(eqIndex + 1) + '");');
-                                    }
-                                });
-
-                                res.needEmptyLine = true;
-
-                                res.line(beanVarName + '.' + $generatorJava.setterName(propName) + '(' + descr.propVarName + ');');
-                            }
-                            break;
-
-                        case 'bean':
-                            if ($generatorCommon.isDefinedAndNotEmpty(bean[propName]))
-                                res.line(beanVarName + '.' + $generatorJava.setterName(propName) + '(new ' + res.importClass(bean[propName]) + '());');
-
-                            break;
-
-                        default:
-                            $generatorJava.property(res, beanVarName, bean, propName, null, descr.setterName, descr.dflt);
-                    }
-                }
-                else
-                    $generatorJava.property(res, beanVarName, bean, propName);
-            }
-        });
-
-        res.needEmptyLine = true;
-
-        res.line(varName + '.' + $generatorJava.setterName(beanPropName) + '(' + beanVarName + ');');
-
-        res.needEmptyLine = true;
-    }
-    else if (createBeanAlthoughNoProps) {
-        res.emptyLineIfNeeded();
-        res.line(varName + '.' + $generatorJava.setterName(beanPropName) + '(new ' + res.importClass(beanClass) + '());');
-
-        res.needEmptyLine = true;
-    }
-};
-
-/**
- * Add eviction policy.
- *
- * @param res Resulting output with generated code.
- * @param varName Current using variable name.
- * @param evtPlc Data to add.
- * @param propName Name in source data.
- */
-$generatorJava.evictionPolicy = function(res, varName, evtPlc, propName) {
-    if (evtPlc && evtPlc.kind) {
-        const evictionPolicyDesc = $generatorCommon.EVICTION_POLICIES[evtPlc.kind];
-
-        const obj = evtPlc[evtPlc.kind.toUpperCase()];
-
-        $generatorJava.beanProperty(res, varName, obj, propName, propName,
-            evictionPolicyDesc.className, evictionPolicyDesc.fields, true);
-    }
-};
-
-// Generate cluster general group.
-$generatorJava.clusterGeneral = function(cluster, clientNearCfg, res) {
-    if (!res)
-        res = $generatorCommon.builder();
-
-    $generatorJava.declareVariable(res, 'cfg', 'org.apache.ignite.configuration.IgniteConfiguration');
-
-    $generatorJava.property(res, 'cfg', cluster, 'name', null, 'setGridName');
-    res.needEmptyLine = true;
-
-    $generatorJava.property(res, 'cfg', cluster, 'localHost');
-    res.needEmptyLine = true;
-
-    if (clientNearCfg) {
-        res.line('cfg.setClientMode(true);');
-
-        res.needEmptyLine = true;
-    }
-
-    if (cluster.discovery) {
-        const d = cluster.discovery;
-
-        $generatorJava.declareVariable(res, 'discovery', 'org.apache.ignite.spi.discovery.tcp.TcpDiscoverySpi');
-
-        switch (d.kind) {
-            case 'Multicast':
-                $generatorJava.beanProperty(res, 'discovery', d.Multicast, 'ipFinder', 'ipFinder',
-                    'org.apache.ignite.spi.discovery.tcp.ipfinder.multicast.TcpDiscoveryMulticastIpFinder',
-                    {
-                        multicastGroup: null,
-                        multicastPort: null,
-                        responseWaitTime: null,
-                        addressRequestAttempts: null,
-                        localAddress: null,
-                        addresses: {type: 'list'}
-                    }, true);
-
-                break;
-
-            case 'Vm':
-                $generatorJava.beanProperty(res, 'discovery', d.Vm, 'ipFinder', 'ipFinder',
-                    'org.apache.ignite.spi.discovery.tcp.ipfinder.vm.TcpDiscoveryVmIpFinder',
-                    {addresses: {type: 'list'}}, true);
-
-                break;
-
-            case 'S3':
-                $generatorJava.beanProperty(res, 'discovery', d.S3, 'ipFinder', 'ipFinder',
-                    'org.apache.ignite.spi.discovery.tcp.ipfinder.s3.TcpDiscoveryS3IpFinder', {bucketName: null}, true);
-
-                break;
-
-            case 'Cloud':
-                $generatorJava.beanProperty(res, 'discovery', d.Cloud, 'ipFinder', 'ipFinder',
-                    'org.apache.ignite.spi.discovery.tcp.ipfinder.cloud.TcpDiscoveryCloudIpFinder',
-                    {
-                        credential: null,
-                        credentialPath: null,
-                        identity: null,
-                        provider: null,
-                        regions: {type: 'list'},
-                        zones: {type: 'list'}
-                    }, true);
-
-                break;
-
-            case 'GoogleStorage':
-                $generatorJava.beanProperty(res, 'discovery', d.GoogleStorage, 'ipFinder', 'ipFinder',
-                    'org.apache.ignite.spi.discovery.tcp.ipfinder.gce.TcpDiscoveryGoogleStorageIpFinder',
-                    {
-                        projectName: null,
-                        bucketName: null,
-                        serviceAccountP12FilePath: null,
-                        serviceAccountId: null
-                    }, true);
-
-                break;
-
-            case 'Jdbc':
-                $generatorJava.beanProperty(res, 'discovery', d.Jdbc, 'ipFinder', 'ipFinder',
-                    'org.apache.ignite.spi.discovery.tcp.ipfinder.jdbc.TcpDiscoveryJdbcIpFinder', {initSchema: null}, true);
-
-                break;
-
-            case 'SharedFs':
-                $generatorJava.beanProperty(res, 'discovery', d.SharedFs, 'ipFinder', 'ipFinder',
-                    'org.apache.ignite.spi.discovery.tcp.ipfinder.sharedfs.TcpDiscoverySharedFsIpFinder', {path: null}, true);
-
-                break;
-
-            case 'ZooKeeper':
-                const finderVar = 'ipFinder';
-
-                $generatorJava.declareVariable(res, 'ipFinder', 'org.apache.ignite.spi.discovery.tcp.ipfinder.zk.TcpDiscoveryZookeeperIpFinder');
-
-                if (d.ZooKeeper) {
-                    if ($generatorCommon.isDefinedAndNotEmpty(d.ZooKeeper.curator))
-                        res.line(finderVar + '.setCurator(new ' + res.importClass(d.ZooKeeper.curator) + '());');
-
-                    $generatorJava.property(res, finderVar, d.ZooKeeper, 'zkConnectionString');
-
-                    if (d.ZooKeeper.retryPolicy && d.ZooKeeper.retryPolicy.kind) {
-                        const kind = d.ZooKeeper.retryPolicy.kind;
-                        const retryPolicy = d.ZooKeeper.retryPolicy[kind];
-
-                        switch (kind) {
-                            case 'ExponentialBackoff':
-                                res.line(finderVar + '.setRetryPolicy(new ' + res.importClass('org.apache.curator.retry.ExponentialBackoffRetry') + '(' +
-                                    $generatorJava.constructorArg(retryPolicy, 'baseSleepTimeMs', 1000) +
-                                    $generatorJava.constructorArg(retryPolicy, 'maxRetries', 10, true) +
-                                    $generatorJava.constructorArg(retryPolicy, 'maxSleepMs', null, true, true) + '));');
-
-                                break;
-
-                            case 'BoundedExponentialBackoff':
-                                res.line(finderVar + '.setRetryPolicy(new ' + res.importClass('org.apache.curator.retry.BoundedExponentialBackoffRetry') + '(' +
-                                    $generatorJava.constructorArg(retryPolicy, 'baseSleepTimeMs', 1000) +
-                                    $generatorJava.constructorArg(retryPolicy, 'maxSleepTimeMs', 2147483647, true) +
-                                    $generatorJava.constructorArg(retryPolicy, 'maxRetries', 10, true) + '));');
-
-                                break;
-
-                            case 'UntilElapsed':
-                                res.line(finderVar + '.setRetryPolicy(new ' + res.importClass('org.apache.curator.retry.RetryUntilElapsed') + '(' +
-                                    $generatorJava.constructorArg(retryPolicy, 'maxElapsedTimeMs', 60000) +
-                                    $generatorJava.constructorArg(retryPolicy, 'sleepMsBetweenRetries', 1000, true) + '));');
-
-                                break;
-
-                            case 'NTimes':
-                                res.line(finderVar + '.setRetryPolicy(new ' + res.importClass('org.apache.curator.retry.RetryNTimes') + '(' +
-                                    $generatorJava.constructorArg(retryPolicy, 'n', 10) +
-                                    $generatorJava.constructorArg(retryPolicy, 'sleepMsBetweenRetries', 1000, true) + '));');
-
-                                break;
-
-                            case 'OneTime':
-                                res.line(finderVar + '.setRetryPolicy(new ' + res.importClass('org.apache.curator.retry.RetryOneTime') + '(' +
-                                    $generatorJava.constructorArg(retryPolicy, 'sleepMsBetweenRetry', 1000) + '));');
-
-                                break;
-
-                            case 'Forever':
-                                res.line(finderVar + '.setRetryPolicy(new ' + res.importClass('org.apache.curator.retry.RetryForever') + '(' +
-                                    $generatorJava.constructorArg(retryPolicy, 'retryIntervalMs', 1000) + '));');
-
-                                break;
-
-                            case 'Custom':
-                                if (retryPolicy && $generatorCommon.isDefinedAndNotEmpty(retryPolicy.className))
-                                    res.line(finderVar + '.setRetryPolicy(new ' + res.importClass(retryPolicy.className) + '());');
-
-                                break;
-
-                            default:
-                        }
-                    }
-
-                    $generatorJava.property(res, finderVar, d.ZooKeeper, 'basePath', null, null, '/services');
-                    $generatorJava.property(res, finderVar, d.ZooKeeper, 'serviceName', null, null, 'ignite');
-                    $generatorJava.property(res, finderVar, d.ZooKeeper, 'allowDuplicateRegistrations', null, null, false);
-                }
-
-                res.line('discovery.setIpFinder(ipFinder);');
-
-                break;
-
-            default:
-                res.line('Unknown discovery kind: ' + d.kind);
-        }
-
-        res.needEmptyLine = false;
-
-        $generatorJava.clusterDiscovery(d, res);
-
-        res.emptyLineIfNeeded();
-
-        res.line('cfg.setDiscoverySpi(discovery);');
-
-        res.needEmptyLine = true;
-    }
-
-    return res;
-};
-
-// Generate atomics group.
-$generatorJava.clusterAtomics = function(atomics, res) {
-    if (!res)
-        res = $generatorCommon.builder();
-
-    if ($generatorCommon.hasAtLeastOneProperty(atomics, ['cacheMode', 'atomicSequenceReserveSize', 'backups'])) {
-        res.startSafeBlock();
-
-        $generatorJava.declareVariable(res, 'atomicCfg', 'org.apache.ignite.configuration.AtomicConfiguration');
-
-        $generatorJava.enumProperty(res, 'atomicCfg', atomics, 'cacheMode', 'org.apache.ignite.cache.CacheMode', null, 'PARTITIONED');
-
-        const cacheMode = atomics.cacheMode ? atomics.cacheMode : 'PARTITIONED';
-
-        let hasData = cacheMode !== 'PARTITIONED';
-
-        hasData = $generatorJava.property(res, 'atomicCfg', atomics, 'atomicSequenceReserveSize', null, null, 1000) || hasData;
-
-        if (cacheMode === 'PARTITIONED')
-            hasData = $generatorJava.property(res, 'atomicCfg', atomics, 'backups', null, null, 0) || hasData;
-
-        res.needEmptyLine = true;
-
-        res.line('cfg.setAtomicConfiguration(atomicCfg);');
-
-        res.needEmptyLine = true;
-
-        if (!hasData)
-            res.rollbackSafeBlock();
-    }
-
-    return res;
-};
-
-// Generate binary group.
-$generatorJava.clusterBinary = function(binary, res) {
-    if (!res)
-        res = $generatorCommon.builder();
-
-    if ($generatorCommon.binaryIsDefined(binary)) {
-        const varName = 'binary';
-
-        $generatorJava.declareVariable(res, varName, 'org.apache.ignite.configuration.BinaryConfiguration');
-
-        if ($generatorCommon.isDefinedAndNotEmpty(binary.idMapper))
-            res.line(varName + '.setIdMapper(new ' + res.importClass(binary.idMapper) + '());');
-
-        if ($generatorCommon.isDefinedAndNotEmpty(binary.nameMapper))
-            res.line(varName + '.setNameMapper(new ' + res.importClass(binary.nameMapper) + '());');
-
-        if ($generatorCommon.isDefinedAndNotEmpty(binary.serializer))
-            res.line(varName + '.setSerializer(new ' + res.importClass(binary.serializer) + '());');
-
-        res.needEmptyLine = $generatorCommon.isDefinedAndNotEmpty(binary.idMapper) || $generatorCommon.isDefinedAndNotEmpty(binary.serializer);
-
-        if ($generatorCommon.isDefinedAndNotEmpty(binary.typeConfigurations)) {
-            const arrVar = 'types';
-
-            $generatorJava.declareVariable(res, arrVar, 'java.util.Collection', 'java.util.ArrayList', 'org.apache.ignite.binary.BinaryTypeConfiguration');
-
-            _.forEach(binary.typeConfigurations, function(type) {
-                if ($generatorCommon.isDefinedAndNotEmpty(type.typeName))
-                    res.line(arrVar + '.add(' + $generatorJava.binaryTypeFunctionName(type.typeName) + '());'); // TODO IGNITE-2269 Replace using of separated methods for binary type configurations to extended constructors.
-            });
-
-            res.needEmptyLine = true;
-
-            res.line(varName + '.setTypeConfigurations(' + arrVar + ');');
-
-            res.needEmptyLine = true;
-        }
-
-        $generatorJava.property(res, varName, binary, 'compactFooter', null, null, true);
-
-        res.needEmptyLine = true;
-
-        res.line('cfg.setBinaryConfiguration(' + varName + ');');
-
-        res.needEmptyLine = true;
-    }
-
-    return res;
-};
-
-// TODO IGNITE-2269 Remove specified methods after implamentation of extended constructors.
-// Construct binary type configuration factory method name.
-$generatorJava.binaryTypeFunctionName = function(typeName) {
-    const dotIdx = typeName.lastIndexOf('.');
-
-    const shortName = dotIdx > 0 ? typeName.substr(dotIdx + 1) : typeName;
-
-    return $generatorCommon.toJavaName('binaryType', shortName);
-};
-
-// TODO IGNITE-2269 Remove specified methods after implamentation of extended constructors.
-// Generate factory method for specified BinaryTypeConfiguration.
-$generatorJava.binaryTypeConfiguration = function(type, res) {
-    const typeName = type.typeName;
-
-    res.line('/**');
-    res.line(' * Create binary type configuration for ' + typeName + '.');
-    res.line(' *');
-    res.line(' * @return Configured binary type.');
-    res.line(' */');
-    res.startBlock('private static BinaryTypeConfiguration ' + $generatorJava.binaryTypeFunctionName(typeName) + '() {');
-
-    $generatorJava.resetVariables(res);
-
-    const typeVar = 'typeCfg';
-
-    $generatorJava.declareVariable(res, typeVar, 'org.apache.ignite.binary.BinaryTypeConfiguration');
-
-    $generatorJava.property(res, typeVar, type, 'typeName');
-
-    if ($generatorCommon.isDefinedAndNotEmpty(type.idMapper))
-        res.line(typeVar + '.setIdMapper(new ' + res.importClass(type.idMapper) + '());');
-
-    if ($generatorCommon.isDefinedAndNotEmpty(type.nameMapper))
-        res.line(typeVar + '.setNameMapper(new ' + res.importClass(type.nameMapper) + '());');
-
-    if ($generatorCommon.isDefinedAndNotEmpty(type.serializer))
-        res.line(typeVar + '.setSerializer(new ' + res.importClass(type.serializer) + '());');
-
-    $generatorJava.property(res, typeVar, type, 'enum', null, null, false);
-
-    res.needEmptyLine = true;
-
-    res.line('return ' + typeVar + ';');
-    res.endBlock('}');
-
-    res.needEmptyLine = true;
-};
-
-// TODO IGNITE-2269 Remove specified methods after implamentation of extended constructors.
-// Generates binary type configuration factory methods.
-$generatorJava.binaryTypeConfigurations = function(binary, res) {
-    if (!res)
-        res = $generatorCommon.builder();
-
-    if (!_.isNil(binary)) {
-        _.forEach(binary.typeConfigurations, function(type) {
-            $generatorJava.binaryTypeConfiguration(type, res);
-        });
-    }
-
-    return res;
-};
-
-// Generate collision group.
-$generatorJava.clusterCollision = function(collision, res) {
-    if (!res)
-        res = $generatorCommon.builder();
-
-    if (collision && collision.kind && collision.kind !== 'Noop') {
-        const spi = collision[collision.kind];
-
-        if (collision.kind !== 'Custom' || (spi && $generatorCommon.isDefinedAndNotEmpty(spi.class))) {
-            const varName = 'collisionSpi';
-
-            switch (collision.kind) {
-                case 'JobStealing':
-                    $generatorJava.declareVariable(res, varName, 'org.apache.ignite.spi.collision.jobstealing.JobStealingCollisionSpi');
-
-                    $generatorJava.property(res, varName, spi, 'activeJobsThreshold', null, null, 95);
-                    $generatorJava.property(res, varName, spi, 'waitJobsThreshold', null, null, 0);
-                    $generatorJava.property(res, varName, spi, 'messageExpireTime', null, null, 1000);
-                    $generatorJava.property(res, varName, spi, 'maximumStealingAttempts', null, null, 5);
-                    $generatorJava.property(res, varName, spi, 'stealingEnabled', null, null, true);
-
-                    if ($generatorCommon.isDefinedAndNotEmpty(spi.externalCollisionListener)) {
-                        res.line(varName + '.' + $generatorJava.setterName('externalCollisionListener') +
-                            '(new ' + res.importClass(spi.externalCollisionListener) + '());');
-                    }
-
-                    if ($generatorCommon.isDefinedAndNotEmpty(spi.stealingAttributes)) {
-                        const stealingAttrsVar = 'stealingAttrs';
-
-                        res.needEmptyLine = true;
-
-                        $generatorJava.declareVariable(res, stealingAttrsVar, 'java.util.Map', 'java.util.HashMap', 'String', 'java.io.Serializable');
-
-                        _.forEach(spi.stealingAttributes, function(attr) {
-                            res.line(stealingAttrsVar + '.put("' + attr.name + '", "' + attr.value + '");');
-                        });
-
-                        res.needEmptyLine = true;
-
-                        res.line(varName + '.setStealingAttributes(' + stealingAttrsVar + ');');
-                    }
-
-                    break;
-
-                case 'FifoQueue':
-                    $generatorJava.declareVariable(res, varName, 'org.apache.ignite.spi.collision.fifoqueue.FifoQueueCollisionSpi');
-
-                    $generatorJava.property(res, varName, spi, 'parallelJobsNumber');
-                    $generatorJava.property(res, varName, spi, 'waitingJobsNumber');
-
-                    break;
-
-                case 'PriorityQueue':
-                    $generatorJava.declareVariable(res, varName, 'org.apache.ignite.spi.collision.priorityqueue.PriorityQueueCollisionSpi');
-
-                    $generatorJava.property(res, varName, spi, 'parallelJobsNumber');
-                    $generatorJava.property(res, varName, spi, 'waitingJobsNumber');
-                    $generatorJava.property(res, varName, spi, 'priorityAttributeKey', null, null, 'grid.task.priority');
-                    $generatorJava.property(res, varName, spi, 'jobPriorityAttributeKey', null, null, 'grid.job.priority');
-                    $generatorJava.property(res, varName, spi, 'defaultPriority', null, null, 0);
-                    $generatorJava.property(res, varName, spi, 'starvationIncrement', null, null, 1);
-                    $generatorJava.property(res, varName, spi, 'starvationPreventionEnabled', null, null, true);
-
-                    break;
-
-                case 'Custom':
-                    $generatorJava.declareVariable(res, varName, spi.class);
-
-                    break;
-
-                default:
-            }
-
-            res.needEmptyLine = true;
-
-            res.line('cfg.setCollisionSpi(' + varName + ');');
-
-            res.needEmptyLine = true;
-        }
-    }
-
-    return res;
-};
-
-// Generate communication group.
-$generatorJava.clusterCommunication = function(cluster, res) {
-    if (!res)
-        res = $generatorCommon.builder();
-
-    const cfg = $generatorCommon.COMMUNICATION_CONFIGURATION;
-
-    $generatorJava.beanProperty(res, 'cfg', cluster.communication, 'communicationSpi', 'commSpi', cfg.className, cfg.fields);
-
-    res.needEmptyLine = false;
-
-    $generatorJava.property(res, 'cfg', cluster, 'networkTimeout', null, null, 5000);
-    $generatorJava.property(res, 'cfg', cluster, 'networkSendRetryDelay', null, null, 1000);
-    $generatorJava.property(res, 'cfg', cluster, 'networkSendRetryCount', null, null, 3);
-    $generatorJava.property(res, 'cfg', cluster, 'segmentCheckFrequency');
-    $generatorJava.property(res, 'cfg', cluster, 'waitForSegmentOnStart', null, null, false);
-    $generatorJava.property(res, 'cfg', cluster, 'discoveryStartupDelay', null, null, 60000);
-
-    res.needEmptyLine = true;
-
-    return res;
-};
-
-// Generate REST access group.
-$generatorJava.clusterConnector = function(connector, res) {
-    if (!res)
-        res = $generatorCommon.builder();
-
-    if (!_.isNil(connector) && connector.enabled) {
-        const cfg = _.cloneDeep($generatorCommon.CONNECTOR_CONFIGURATION);
-
-        if (connector.sslEnabled) {
-            cfg.fields.sslClientAuth = {dflt: false};
-            cfg.fields.sslFactory = {type: 'bean'};
-        }
-
-        $generatorJava.beanProperty(res, 'cfg', connector, 'connectorConfiguration', 'clientCfg',
-            cfg.className, cfg.fields, true);
-
-        res.needEmptyLine = true;
-    }
-
-    return res;
-};
-
-// Generate deployment group.
-$generatorJava.clusterDeployment = function(cluster, res) {
-    if (!res)
-        res = $generatorCommon.builder();
-
-    $generatorJava.enumProperty(res, 'cfg', cluster, 'deploymentMode', 'org.apache.ignite.configuration.DeploymentMode', null, 'SHARED');
-
-    res.softEmptyLine();
-
-    const p2pEnabled = cluster.peerClassLoadingEnabled;
-
-    if (!_.isNil(p2pEnabled)) {
-        $generatorJava.property(res, 'cfg', cluster, 'peerClassLoadingEnabled', null, null, false);
-
-        if (p2pEnabled) {
-            $generatorJava.property(res, 'cfg', cluster, 'peerClassLoadingMissedResourcesCacheSize', null, null, 100);
-            $generatorJava.property(res, 'cfg', cluster, 'peerClassLoadingThreadPoolSize', null, null, 2);
-            $generatorJava.multiparamProperty(res, 'cfg', cluster, 'peerClassLoadingLocalClassPathExclude');
-        }
-
-        res.needEmptyLine = true;
-    }
-
-    return res;
-};
-
-// Generate discovery group.
-$generatorJava.clusterDiscovery = function(disco, res) {
-    if (!res)
-        res = $generatorCommon.builder();
-
-    if (disco) {
-        $generatorJava.property(res, 'discovery', disco, 'localAddress');
-        $generatorJava.property(res, 'discovery', disco, 'localPort', null, null, 47500);
-        $generatorJava.property(res, 'discovery', disco, 'localPortRange', null, null, 100);
-
-        if ($generatorCommon.isDefinedAndNotEmpty(disco.addressResolver)) {
-            $generatorJava.beanProperty(res, 'discovery', disco, 'addressResolver', 'addressResolver', disco.addressResolver, {}, true);
-            res.needEmptyLine = false;
-        }
-
-        $generatorJava.property(res, 'discovery', disco, 'socketTimeout', null, null, 5000);
-        $generatorJava.property(res, 'discovery', disco, 'ackTimeout', null, null, 5000);
-        $generatorJava.property(res, 'discovery', disco, 'maxAckTimeout', null, null, 600000);
-        $generatorJava.property(res, 'discovery', disco, 'networkTimeout', null, null, 5000);
-        $generatorJava.property(res, 'discovery', disco, 'joinTimeout', null, null, 0);
-        $generatorJava.property(res, 'discovery', disco, 'threadPriority', null, null, 10);
-        $generatorJava.property(res, 'discovery', disco, 'heartbeatFrequency', null, null, 2000);
-        $generatorJava.property(res, 'discovery', disco, 'maxMissedHeartbeats', null, null, 1);
-        $generatorJava.property(res, 'discovery', disco, 'maxMissedClientHeartbeats', null, null, 5);
-        $generatorJava.property(res, 'discovery', disco, 'topHistorySize', null, null, 1000);
-
-        if ($generatorCommon.isDefinedAndNotEmpty(disco.listener)) {
-            $generatorJava.beanProperty(res, 'discovery', disco, 'listener', 'listener', disco.listener, {}, true);
-            res.needEmptyLine = false;
-        }
-
-        if ($generatorCommon.isDefinedAndNotEmpty(disco.dataExchange)) {
-            $generatorJava.beanProperty(res, 'discovery', disco, 'dataExchange', 'dataExchange', disco.dataExchange, {}, true);
-            res.needEmptyLine = false;
-        }
-
-        if ($generatorCommon.isDefinedAndNotEmpty(disco.metricsProvider)) {
-            $generatorJava.beanProperty(res, 'discovery', disco, 'metricsProvider', 'metricsProvider', disco.metricsProvider, {}, true);
-            res.needEmptyLine = false;
-        }
-
-        $generatorJava.property(res, 'discovery', disco, 'reconnectCount', null, null, 10);
-        $generatorJava.property(res, 'discovery', disco, 'statisticsPrintFrequency', null, null, 0);
-        $generatorJava.property(res, 'discovery', disco, 'ipFinderCleanFrequency', null, null, 60000);
-
-        if ($generatorCommon.isDefinedAndNotEmpty(disco.authenticator)) {
-            $generatorJava.beanProperty(res, 'discovery', disco, 'authenticator', 'authenticator', disco.authenticator, {}, true);
-            res.needEmptyLine = false;
-        }
-
-        $generatorJava.property(res, 'discovery', disco, 'forceServerMode', null, null, false);
-        $generatorJava.property(res, 'discovery', disco, 'clientReconnectDisabled', null, null, false);
-
-        res.needEmptyLine = true;
-    }
-
-    return res;
-};
-
-// Generate events group.
-$generatorJava.clusterEvents = function(cluster, res) {
-    if (!res)
-        res = $generatorCommon.builder();
-
-    if (cluster.includeEventTypes && cluster.includeEventTypes.length > 0) {
-        res.emptyLineIfNeeded();
-
-        const evtGrps = angular.element(document.getElementById('app')).injector().get('igniteEventGroups');
-
-        if (cluster.includeEventTypes.length === 1) {
-            const evtGrp = _.find(evtGrps, {value: cluster.includeEventTypes[0]});
-            const evts = res.importStatic(evtGrp.class + '.' + evtGrp.value);
-
-            res.line('cfg.setIncludeEventTypes(' + evts + ');');
-        }
-        else {
-            _.forEach(cluster.includeEventTypes, function(value, ix) {
-                const evtGrp = _.find(evtGrps, {value});
-                const evts = res.importStatic(evtGrp.class + '.' + evtGrp.value);
-
-                if (ix === 0)
-                    res.line('int[] events = new int[' + evts + '.length');
-                else
-                    res.line('    + ' + evts + '.length');
-            });
-
-            res.line('];');
-
-            res.needEmptyLine = true;
-
-            res.line('int k = 0;');
-
-            _.forEach(cluster.includeEventTypes, function(value, idx) {
-                res.needEmptyLine = true;
-
-                const evtGrp = _.find(evtGrps, {value});
-                const evts = res.importStatic(evtGrp.class + '.' + value);
-
-                res.line('System.arraycopy(' + evts + ', 0, events, k, ' + evts + '.length);');
-
-                if (idx < cluster.includeEventTypes.length - 1)
-                    res.line('k += ' + evts + '.length;');
-            });
-
-            res.needEmptyLine = true;
-
-            res.line('cfg.setIncludeEventTypes(events);');
-        }
-
-        res.needEmptyLine = true;
-    }
-
-    res.needEmptyLine = true;
-
-    return res;
-};
-
-// Generate failover group.
-$generatorJava.clusterFailover = function(cluster, res) {
-    if (!res)
-        res = $generatorCommon.builder();
-
-    if ($generatorCommon.isDefinedAndNotEmpty(cluster.failoverSpi) && _.findIndex(cluster.failoverSpi, function(spi) {
-        return $generatorCommon.isDefinedAndNotEmpty(spi.kind) && (spi.kind !== 'Custom' || $generatorCommon.isDefinedAndNotEmpty(_.get(spi, spi.kind + '.class')));
-    }) >= 0) {
-        const arrayVarName = 'failoverSpiList';
-
-        $generatorJava.declareVariable(res, arrayVarName, 'java.util.List', 'java.util.ArrayList', 'org.apache.ignite.spi.failover.FailoverSpi');
-
-        _.forEach(cluster.failoverSpi, function(spi) {
-            if (spi.kind && (spi.kind !== 'Custom' || $generatorCommon.isDefinedAndNotEmpty(_.get(spi, spi.kind + '.class')))) {
-                const varName = 'failoverSpi';
-
-                const maxAttempts = _.get(spi, spi.kind + '.maximumFailoverAttempts');
-
-                if ((spi.kind === 'JobStealing' || spi.kind === 'Always') && $generatorCommon.isDefinedAndNotEmpty(maxAttempts) && maxAttempts !== 5) {
-                    const spiCls = res.importClass($generatorCommon.failoverSpiClass(spi));
-
-                    $generatorJava.declareVariableCustom(res, varName, 'org.apache.ignite.spi.failover.FailoverSpi', 'new ' + spiCls + '()');
-
-                    if ($generatorCommon.isDefinedAndNotEmpty(spi[spi.kind].maximumFailoverAttempts))
-                        res.line('((' + spiCls + ') ' + varName + ').setMaximumFailoverAttempts(' + spi[spi.kind].maximumFailoverAttempts + ');');
-
-                    res.needEmptyLine = true;
-
-                    res.line(arrayVarName + '.add(' + varName + ');');
-                }
-                else
-                    res.line(arrayVarName + '.add(new ' + res.importClass($generatorCommon.failoverSpiClass(spi)) + '());');
-
-                res.needEmptyLine = true;
-            }
-        });
-
-        res.line('cfg.setFailoverSpi(' + arrayVarName + '.toArray(new FailoverSpi[' + arrayVarName + '.size()]));');
-
-        res.needEmptyLine = true;
-    }
-
-    return res;
-};
-
-// Generate marshaller group.
-$generatorJava.clusterLogger = function(logger, res) {
-    if (!res)
-        res = $generatorCommon.builder();
-
-    if ($generatorCommon.loggerConfigured(logger)) {
-        const varName = 'logger';
-
-        const log = logger[logger.kind];
-
-        switch (logger.kind) {
-            case 'Log4j2':
-                $generatorJava.declareVariableCustom(res, varName, 'org.apache.ignite.logger.log4j2.Log4J2Logger',
-                    'new Log4J2Logger(' + $generatorJava.toJavaCode(log.path, 'path') + ')');
-
-                res.needEmptyLine = true;
-
-                if ($generatorCommon.isDefinedAndNotEmpty(log.level))
-                    res.line(varName + '.setLevel(' + res.importClass('org.apache.logging.log4j.Level') + '.' + log.level + ');');
-
-                break;
-
-            case 'Null':
-                $generatorJava.declareVariable(res, varName, 'org.apache.ignite.logger.NullLogger');
-
-                break;
-
-            case 'Java':
-                $generatorJava.declareVariable(res, varName, 'org.apache.ignite.logger.java.JavaLogger');
-
-                break;
-
-            case 'JCL':
-                $generatorJava.declareVariable(res, varName, 'org.apache.ignite.logger.jcl.JclLogger');
-
-                break;
-
-            case 'SLF4J':
-                $generatorJava.declareVariable(res, varName, 'org.apache.ignite.logger.slf4j.Slf4jLogger');
-
-                break;
-
-            case 'Log4j':
-                if (log.mode === 'Default')
-                    $generatorJava.declareVariable(res, varName, 'org.apache.ignite.logger.log4j.Log4JLogger');
-                else {
-                    $generatorJava.declareVariableCustom(res, varName, 'org.apache.ignite.logger.log4j.Log4JLogger',
-                        'new Log4JLogger(' + $generatorJava.toJavaCode(log.path, 'path') + ')');
-                }
-
-                if ($generatorCommon.isDefinedAndNotEmpty(log.level))
-                    res.line(varName + '.setLevel(' + res.importClass('org.apache.log4j.Level') + '.' + log.level + ');');
-
-                break;
-
-            case 'Custom':
-                $generatorJava.declareVariable(res, varName, log.class);
-
-                break;
-
-            default:
-        }
-
-        res.needEmptyLine = true;
-
-        res.line('cfg.setGridLogger(' + varName + ');');
-
-        res.needEmptyLine = true;
-    }
-
-    return res;
-};
-
-// Generate marshaller group.
-$generatorJava.clusterMarshaller = function(cluster, res) {
-    if (!res)
-        res = $generatorCommon.builder();
-
-    const marshaller = cluster.marshaller;
-
-    if (marshaller && marshaller.kind) {
-        const marshallerDesc = $generatorCommon.MARSHALLERS[marshaller.kind];
-
-        $generatorJava.beanProperty(res, 'cfg', marshaller[marshaller.kind], 'marshaller', 'marshaller',
-            marshallerDesc.className, marshallerDesc.fields, true);
-
-        $generatorJava.beanProperty(res, 'marshaller', marshaller[marshaller.kind], marshallerDesc.className, marshallerDesc.fields, true);
-    }
-
-    $generatorJava.property(res, 'cfg', cluster, 'marshalLocalJobs', null, null, false);
-    $generatorJava.property(res, 'cfg', cluster, 'marshallerCacheKeepAliveTime', null, null, 10000);
-    $generatorJava.property(res, 'cfg', cluster, 'marshallerCacheThreadPoolSize', null, 'setMarshallerCachePoolSize');
-
-    res.needEmptyLine = true;
-
-    return res;
-};
-
-// Generate metrics group.
-$generatorJava.clusterMetrics = function(cluster, res) {
-    if (!res)
-        res = $generatorCommon.builder();
-
-    $generatorJava.property(res, 'cfg', cluster, 'metricsExpireTime');
-    $generatorJava.property(res, 'cfg', cluster, 'metricsHistorySize', null, null, 10000);
-    $generatorJava.property(res, 'cfg', cluster, 'metricsLogFrequency', null, null, 60000);
-    $generatorJava.property(res, 'cfg', cluster, 'metricsUpdateFrequency', null, null, 2000);
-
-    res.needEmptyLine = true;
-
-    return res;
-};
-
-// Generate swap group.
-$generatorJava.clusterSwap = function(cluster, res) {
-    if (!res)
-        res = $generatorCommon.builder();
-
-    if (cluster.swapSpaceSpi && cluster.swapSpaceSpi.kind === 'FileSwapSpaceSpi') {
-        $generatorJava.beanProperty(res, 'cfg', cluster.swapSpaceSpi.FileSwapSpaceSpi, 'swapSpaceSpi', 'swapSpi',
-            $generatorCommon.SWAP_SPACE_SPI.className, $generatorCommon.SWAP_SPACE_SPI.fields, true);
-
-        res.needEmptyLine = true;
-    }
-
-    return res;
-};
-
-// Generate time group.
-$generatorJava.clusterTime = function(cluster, res) {
-    if (!res)
-        res = $generatorCommon.builder();
-
-    $generatorJava.property(res, 'cfg', cluster, 'clockSyncSamples', null, null, 8);
-    $generatorJava.property(res, 'cfg', cluster, 'clockSyncFrequency', null, null, 120000);
-    $generatorJava.property(res, 'cfg', cluster, 'timeServerPortBase', null, null, 31100);
-    $generatorJava.property(res, 'cfg', cluster, 'timeServerPortRange', null, null, 100);
-
-    res.needEmptyLine = true;
-
-    return res;
-};
-
-// Generate thread pools group.
-$generatorJava.clusterPools = function(cluster, res) {
-    if (!res)
-        res = $generatorCommon.builder();
-
-    $generatorJava.property(res, 'cfg', cluster, 'publicThreadPoolSize');
-    $generatorJava.property(res, 'cfg', cluster, 'systemThreadPoolSize');
-    $generatorJava.property(res, 'cfg', cluster, 'managementThreadPoolSize');
-    $generatorJava.property(res, 'cfg', cluster, 'igfsThreadPoolSize');
-    $generatorJava.property(res, 'cfg', cluster, 'rebalanceThreadPoolSize');
-
-    res.needEmptyLine = true;
-
-    return res;
-};
-
-// Generate transactions group.
-$generatorJava.clusterTransactions = function(transactionConfiguration, res) {
-    if (!res)
-        res = $generatorCommon.builder();
-
-    $generatorJava.beanProperty(res, 'cfg', transactionConfiguration, 'transactionConfiguration',
-        'transactionConfiguration', $generatorCommon.TRANSACTION_CONFIGURATION.className,
-        $generatorCommon.TRANSACTION_CONFIGURATION.fields, false);
-
-    return res;
-};
-
-// Generate user attributes group.
-$generatorJava.clusterUserAttributes = function(cluster, res) {
-    if (!res)
-        res = $generatorCommon.builder();
-
-    if ($generatorCommon.isDefinedAndNotEmpty(cluster.attributes)) {
-        $generatorJava.declareVariable(res, 'attributes', 'java.util.Map', 'java.util.HashMap', 'java.lang.String', 'java.lang.String');
-
-        _.forEach(cluster.attributes, function(attr) {
-            res.line('attributes.put("' + attr.name + '", "' + attr.value + '");');
-        });
-
-        res.needEmptyLine = true;
-
-        res.line('cfg.setUserAttributes(attributes);');
-
-        res.needEmptyLine = true;
-    }
-
-    res.needEmptyLine = true;
-
-    return res;
-};
-
-
-// Generate cache general group.
-$generatorJava.cacheGeneral = function(cache, varName, res) {
-    if (!res)
-        res = $generatorCommon.builder();
-
-    if (!varName)
-        varName = $generatorJava.nextVariableName('cache', cache);
-
-    $generatorJava.property(res, varName, cache, 'name');
-
-    $generatorJava.enumProperty(res, varName, cache, 'cacheMode', 'org.apache.ignite.cache.CacheMode');
-    $generatorJava.enumProperty(res, varName, cache, 'atomicityMode', 'org.apache.ignite.cache.CacheAtomicityMode');
-
-    if (cache.cacheMode === 'PARTITIONED' && $generatorJava.property(res, varName, cache, 'backups'))
-        $generatorJava.property(res, varName, cache, 'readFromBackup');
-
-    $generatorJava.property(res, varName, cache, 'copyOnRead');
-
-    if (cache.cacheMode === 'PARTITIONED' && cache.atomicityMode === 'TRANSACTIONAL')
-        $generatorJava.property(res, varName, cache, 'invalidate');
-
-    res.needEmptyLine = true;
-
-    return res;
-};
-
-// Generate cache memory group.
-$generatorJava.cacheMemory = function(cache, varName, res) {
-    if (!res)
-        res = $generatorCommon.builder();
-
-    if (!varName)
-        varName = $generatorJava.nextVariableName('cache', cache);
-
-    $generatorJava.enumProperty(res, varName, cache, 'memoryMode', 'org.apache.ignite.cache.CacheMemoryMode', null, 'ONHEAP_TIERED');
-    $generatorJava.property(res, varName, cache, 'offHeapMaxMemory', null, null, -1);
-
-    res.softEmptyLine();
-
-    $generatorJava.evictionPolicy(res, varName, cache.evictionPolicy, 'evictionPolicy');
-
-    $generatorJava.property(res, varName, cache, 'startSize', null, null, 1500000);
-    $generatorJava.property(res, varName, cache, 'swapEnabled', null, null, false);
-
-    res.needEmptyLine = true;
-
-    return res;
-};
-
-// Generate cache query & indexing group.
-$generatorJava.cacheQuery = function(cache, varName, res) {
-    if (!res)
-        res = $generatorCommon.builder();
-
-    if (!varName)
-        varName = $generatorJava.nextVariableName('cache', cache);
-
-    $generatorJava.property(res, varName, cache, 'sqlSchema');
-    $generatorJava.property(res, varName, cache, 'sqlOnheapRowCacheSize', null, null, 10240);
-    $generatorJava.property(res, varName, cache, 'longQueryWarningTimeout', null, null, 3000);
-
-    res.softEmptyLine();
-
-    $generatorJava.multiparamProperty(res, varName, cache, 'sqlFunctionClasses', 'class');
-
-    res.softEmptyLine();
-
-    $generatorJava.property(res, varName, cache, 'snapshotableIndex', null, null, false);
-    $generatorJava.property(res, varName, cache, 'sqlEscapeAll', null, null, false);
-
-    res.needEmptyLine = true;
-
-    return res;
-};
-
-/**
- * Generate cache store datasource.
- *
- * @param storeFactory Factory to generate data source for.
- * @param res Resulting output with generated code.
- */
-$generatorJava.cacheStoreDataSource = function(storeFactory, res) {
-    const dialect = storeFactory.connectVia ? (storeFactory.connectVia === 'DataSource' ? storeFactory.dialect : null) : storeFactory.dialect;
-
-    if (dialect) {
-        const varName = 'dataSource';
-
-        const dataSourceBean = storeFactory.dataSourceBean;
-
-        const varType = res.importClass($generatorCommon.dataSourceClassName(dialect));
-
-        res.line('public static final ' + varType + ' INSTANCE_' + dataSourceBean + ' = create' + dataSourceBean + '();');
-
-        res.needEmptyLine = true;
-
-        res.startBlock('private static ' + varType + ' create' + dataSourceBean + '() {');
-        if (dialect === 'Oracle')
-            res.startBlock('try {');
-
-        $generatorJava.resetVariables(res);
-
-        $generatorJava.declareVariable(res, varName, varType);
-
-        switch (dialect) {
-            case 'Generic':
-                res.line(varName + '.setJdbcUrl(props.getProperty("' + dataSourceBean + '.jdbc.url"));');
-
-                break;
-
-            case 'DB2':
-                res.line(varName + '.setServerName(props.getProperty("' + dataSourceBean + '.jdbc.server_name"));');
-                res.line(varName + '.setPortNumber(Integer.valueOf(props.getProperty("' + dataSourceBean + '.jdbc.port_number")));');
-                res.line(varName + '.setDatabaseName(props.getProperty("' + dataSourceBean + '.jdbc.database_name"));');
-                res.line(varName + '.setDriverType(Integer.valueOf(props.getProperty("' + dataSourceBean + '.jdbc.driver_type")));');
-
-                break;
-
-            case 'PostgreSQL':
-                res.line(varName + '.setUrl(props.getProperty("' + dataSourceBean + '.jdbc.url"));');
-
-                break;
-
-            default:
-                res.line(varName + '.setURL(props.getProperty("' + dataSourceBean + '.jdbc.url"));');
-        }
-
-        res.line(varName + '.setUser(props.getProperty("' + dataSourceBean + '.jdbc.username"));');
-        res.line(varName + '.setPassword(props.getProperty("' + dataSourceBean + '.jdbc.password"));');
-
-        res.needEmptyLine = true;
-
-        res.line('return dataSource;');
-
-        if (dialect === 'Oracle') {
-            res.endBlock('}');
-            res.startBlock('catch (' + res.importClass('java.sql.SQLException') + ' ex) {');
-            res.line('throw new Error(ex);');
-            res.endBlock('}');
-        }
-
-        res.endBlock('}');
-
-        res.needEmptyLine = true;
-
-        return dataSourceBean;
-    }
-
-    return null;
-};
-
-$generatorJava.clusterDataSources = function(caches, res) {
-    if (!res)
-        res = $generatorCommon.builder();
-
-    const datasources = [];
-
-    let storeFound = false;
-
-    _.forEach(caches, function(cache) {
-        const factoryKind = cache.cacheStoreFactory.kind;
-
-        const storeFactory = cache.cacheStoreFactory[factoryKind];
-
-        if (storeFactory) {
-            const beanClassName = $generatorJava.dataSourceClassName(res, storeFactory);
-
-            if (beanClassName && !_.includes(datasources, beanClassName)) {
-                datasources.push(beanClassName);
-
-                if (factoryKind === 'CacheJdbcPojoStoreFactory' || factoryKind === 'CacheJdbcBlobStoreFactory') {
-                    if (!storeFound) {
-                        res.line('/** Helper class for datasource creation. */');
-                        res.startBlock('public static class DataSources {');
-
-                        storeFound = true;
-                    }
-
-                    $generatorJava.cacheStoreDataSource(storeFactory, res);
-                }
-            }
-        }
-    });
-
-    if (storeFound)
-        res.endBlock('}');
-
-    return res;
-};
-
-/**
- * Generate cache store group.
- *
- * @param cache Cache descriptor.
- * @param domains Domain model descriptors.
- * @param cacheVarName Cache variable name.
- * @param res Resulting output with generated code.
- * @returns {*} Java code for cache store configuration.
- */
-$generatorJava.cacheStore = function(cache, domains, cacheVarName, res) {
-    if (!res)
-        res = $generatorCommon.builder();
-
-    if (!cacheVarName)
-        cacheVarName = $generatorJava.nextVariableName('cache', cache);
-
-    if (cache.cacheStoreFactory && cache.cacheStoreFactory.kind) {
-        const factoryKind = cache.cacheStoreFactory.kind;
-
-        const storeFactory = cache.cacheStoreFactory[factoryKind];
-
-        if (storeFactory) {
-            const storeFactoryDesc = $generatorCommon.STORE_FACTORIES[factoryKind];
-
-            const varName = 'storeFactory' + storeFactoryDesc.suffix;
-
-            if (factoryKind === 'CacheJdbcPojoStoreFactory') {
-                // Generate POJO store factory.
-                $generatorJava.declareVariable(res, varName, 'org.apache.ignite.cache.store.jdbc.CacheJdbcPojoStoreFactory', null, null, null, true);
-                res.deep++;
-
-                res.line('/** {@inheritDoc} */');
-                res.startBlock('@Override public ' + res.importClass('org.apache.ignite.cache.store.jdbc.CacheJdbcPojoStore') + ' create() {');
-
-                res.line('setDataSource(DataSources.INSTANCE_' + storeFactory.dataSourceBean + ');');
-
-                res.needEmptyLine = true;
-
-                res.line('return super.create();');
-                res.endBlock('}');
-                res.endBlock('};');
-
-                res.needEmptyLine = true;
-
-                res.line(varName + '.setDialect(new ' +
-                    res.importClass($generatorCommon.jdbcDialectClassName(storeFactory.dialect)) + '());');
-
-                res.needEmptyLine = true;
-
-                const domainConfigs = _.filter(domains, function(domain) {
-                    return $generatorCommon.domainQueryMetadata(domain) === 'Configuration' &&
-                        $generatorCommon.isDefinedAndNotEmpty(domain.databaseTable);
-                });
-
-                if ($generatorCommon.isDefinedAndNotEmpty(domainConfigs)) {
-                    $generatorJava.declareVariable(res, 'jdbcTypes', 'java.util.Collection', 'java.util.ArrayList', 'org.apache.ignite.cache.store.jdbc.JdbcType');
-
-                    res.needEmptyLine = true;
-
-                    _.forEach(domainConfigs, function(domain) {
-                        if ($generatorCommon.isDefinedAndNotEmpty(domain.databaseTable))
-                            res.line('jdbcTypes.add(jdbcType' + $generatorJava.extractType(domain.valueType) + '(' + cacheVarName + '.getName()));');
-                    });
-
-                    res.needEmptyLine = true;
-
-                    res.line(varName + '.setTypes(jdbcTypes.toArray(new JdbcType[jdbcTypes.size()]));');
-
-                    res.needEmptyLine = true;
-                }
-
-                res.line(cacheVarName + '.setCacheStoreFactory(' + varName + ');');
-            }
-            else if (factoryKind === 'CacheJdbcBlobStoreFactory') {
-                // Generate POJO store factory.
-                $generatorJava.declareVariable(res, varName, 'org.apache.ignite.cache.store.jdbc.CacheJdbcBlobStoreFactory', null, null, null, storeFactory.connectVia === 'DataSource');
-
-                if (storeFactory.connectVia === 'DataSource') {
-                    res.deep++;
-
-                    res.line('/** {@inheritDoc} */');
-                    res.startBlock('@Override public ' + res.importClass('org.apache.ignite.cache.store.jdbc.CacheJdbcBlobStore') + ' create() {');
-
-                    res.line('setDataSource(DataSources.INSTANCE_' + storeFactory.dataSourceBean + ');');
-
-                    res.needEmptyLine = true;
-
-                    res.line('return super.create();');
-                    res.endBlock('}');
-                    res.endBlock('};');
-
-                    res.needEmptyLine = true;
-
-                    $generatorJava.property(res, varName, storeFactory, 'initSchema');
-                    $generatorJava.property(res, varName, storeFactory, 'createTableQuery');
-                    $generatorJava.property(res, varName, storeFactory, 'loadQuery');
-                    $generatorJava.property(res, varName, storeFactory, 'insertQuery');
-                    $generatorJava.property(res, varName, storeFactory, 'updateQuery');
-                    $generatorJava.property(res, varName, storeFactory, 'deleteQuery');
-                }
-                else {
-                    $generatorJava.property(res, varName, storeFactory, 'connectionUrl');
-
-                    if (storeFactory.user) {
-                        $generatorJava.property(res, varName, storeFactory, 'user');
-                        res.line(varName + '.setPassword(props.getProperty("ds.' + storeFactory.user + '.password"));');
-                    }
-                }
-
-                res.needEmptyLine = true;
-
-                res.line(cacheVarName + '.setCacheStoreFactory(' + varName + ');');
-            }
-            else
-                $generatorJava.beanProperty(res, cacheVarName, storeFactory, 'cacheStoreFactory', varName, storeFactoryDesc.className, storeFactoryDesc.fields, true);
-
-            res.needEmptyLine = true;
-        }
-    }
-
-    res.softEmptyLine();
-
-    $generatorJava.property(res, cacheVarName, cache, 'storeKeepBinary', null, null, false);
-    $generatorJava.property(res, cacheVarName, cache, 'loadPreviousValue', null, null, false);
-    $generatorJava.property(res, cacheVarName, cache, 'readThrough', null, null, false);
-    $generatorJava.property(res, cacheVarName, cache, 'writeThrough', null, null, false);
-
-    res.softEmptyLine();
-
-    if (cache.writeBehindEnabled) {
-        $generatorJava.property(res, cacheVarName, cache, 'writeBehindEnabled', null, null, false);
-        $generatorJava.property(res, cacheVarName, cache, 'writeBehindBatchSize', null, null, 512);
-        $generatorJava.property(res, cacheVarName, cache, 'writeBehindFlushSize', null, null, 10240);
-        $generatorJava.property(res, cacheVarName, cache, 'writeBehindFlushFrequency', null, null, 5000);
-        $generatorJava.property(res, cacheVarName, cache, 'writeBehindFlushThreadCount', null, null, 1);
-    }
-
-    res.needEmptyLine = true;
-
-    return res;
-};
-
-// Generate cache concurrency group.
-$generatorJava.cacheConcurrency = function(cache, varName, res) {
-    if (!res)
-        res = $generatorCommon.builder();
-
-    if (!varName)
-        varName = $generatorJava.nextVariableName('cache', cache);
-
-    $generatorJava.property(res, varName, cache, 'maxConcurrentAsyncOperations', null, null, 500);
-    $generatorJava.property(res, varName, cache, 'defaultLockTimeout', null, null, 0);
-    $generatorJava.enumProperty(res, varName, cache, 'atomicWriteOrderMode', 'org.apache.ignite.cache.CacheAtomicWriteOrderMode');
-    $generatorJava.enumProperty(res, varName, cache, 'writeSynchronizationMode', 'org.apache.ignite.cache.CacheWriteSynchronizationMode', null, null, 'PRIMARY_SYNC');
-
-    res.needEmptyLine = true;
-
-    return res;
-};
-
-// Generate cache rebalance group.
-$generatorJava.cacheRebalance = function(cache, varName, res) {
-    if (!res)
-        res = $generatorCommon.builder();
-
-    if (!varName)
-        varName = $generatorJava.nextVariableName('cache', cache);
-
-    if (cache.cacheMode !== 'LOCAL') {
-        $generatorJava.enumProperty(res, varName, cache, 'rebalanceMode', 'org.apache.ignite.cache.CacheRebalanceMode', null, 'ASYNC');
-        $generatorJava.property(res, varName, cache, 'rebalanceThreadPoolSize', null, null, 1);
-        $generatorJava.property(res, varName, cache, 'rebalanceBatchSize', null, null, 524288);
-        $generatorJava.property(res, varName, cache, 'rebalanceBatchesPrefetchCount', null, null, 2);
-        $generatorJava.property(res, varName, cache, 'rebalanceOrder', null, null, 0);
-        $generatorJava.property(res, varName, cache, 'rebalanceDelay', null, null, 0);
-        $generatorJava.property(res, varName, cache, 'rebalanceTimeout', null, null, 10000);
-        $generatorJava.property(res, varName, cache, 'rebalanceThrottle', null, null, 0);
-    }
-
-    res.softEmptyLine();
-
-    if (cache.igfsAffinnityGroupSize) {
-        res.line(varName + '.setAffinityMapper(new ' + res.importClass('org.apache.ignite.igfs.IgfsGroupDataBlocksKeyMapper') + '(' + cache.igfsAffinnityGroupSize + '));');
-
-        res.needEmptyLine = true;
-    }
-
-    return res;
-};
-
-// Generate cache server near cache group.
-$generatorJava.cacheServerNearCache = function(cache, varName, res) {
-    if (!res)
-        res = $generatorCommon.builder();
-
-    if (!varName)
-        varName = $generatorJava.nextVariableName('cache', cache);
-
-    if (cache.cacheMode === 'PARTITIONED' && cache.nearCacheEnabled) {
-        res.needEmptyLine = true;
-
-        if (cache.nearConfiguration) {
-            $generatorJava.declareVariable(res, 'nearCfg', 'org.apache.ignite.configuration.NearCacheConfiguration');
-
-            res.needEmptyLine = true;
-
-            if (cache.nearConfiguration.nearStartSize) {
-                $generatorJava.property(res, 'nearCfg', cache.nearConfiguration, 'nearStartSize', null, null, 375000);
-
-                res.needEmptyLine = true;
-            }
-
-            if (cache.nearConfiguration.nearEvictionPolicy && cache.nearConfiguration.nearEvictionPolicy.kind) {
-                $generatorJava.evictionPolicy(res, 'nearCfg', cache.nearConfiguration.nearEvictionPolicy, 'nearEvictionPolicy');
-
-                res.needEmptyLine = true;
-            }
-
-            res.line(varName + '.setNearConfiguration(nearCfg);');
-
-            res.needEmptyLine = true;
-        }
-    }
-
-    return res;
-};
-
-// Generate cache statistics group.
-$generatorJava.cacheStatistics = function(cache, varName, res) {
-    if (!res)
-        res = $generatorCommon.builder();
-
-    if (!varName)
-        varName = $generatorJava.nextVariableName('cache', cache);
-
-    $generatorJava.property(res, varName, cache, 'statisticsEnabled', null, null, false);
-    $generatorJava.property(res, varName, cache, 'managementEnabled', null, null, false);
-
-    res.needEmptyLine = true;
-
-    return res;
-};
-
-// Generate domain model query fields.
-$generatorJava.domainModelQueryFields = function(res, domain) {
-    const fields = domain.fields;
-
-    if (fields && fields.length > 0) {
-        $generatorJava.declareVariable(res, 'fields', 'java.util.LinkedHashMap', 'java.util.LinkedHashMap', 'java.lang.String', 'java.lang.String');
-
-        _.forEach(fields, function(field) {
-            res.line('fields.put("' + field.name + '", "' + $generatorCommon.JavaTypes.fullClassName(field.className) + '");');
-        });
-
-        res.needEmptyLine = true;
-
-        res.line('qryMeta.setFields(fields);');
-
-        res.needEmptyLine = true;
-    }
-};
-
-// Generate domain model query aliases.
-$generatorJava.domainModelQueryAliases = function(res, domain) {
-    const aliases = domain.aliases;
-
-    if (aliases && aliases.length > 0) {
-        $generatorJava.declareVariable(res, 'aliases', 'java.util.Map', 'java.util.HashMap', 'java.lang.String', 'java.lang.String');
-
-        _.forEach(aliases, function(alias) {
-            res.line('aliases.put("' + alias.field + '", "' + alias.alias + '");');
-        });
-
-        res.needEmptyLine = true;
-
-        res.line('qryMeta.setAliases(aliases);');
-
-        res.needEmptyLine = true;
-    }
-};
-
-// Generate domain model indexes.
-$generatorJava.domainModelQueryIndexes = function(res, domain) {
-    const indexes = domain.indexes;
-
-    if (indexes && indexes.length > 0) {
-        res.needEmptyLine = true;
-
-        $generatorJava.declareVariable(res, 'indexes', 'java.util.List', 'java.util.ArrayList', 'org.apache.ignite.cache.QueryIndex');
-
-        _.forEach(indexes, function(index) {
-            const fields = index.fields;
-
-            // One row generation for 1 field index.
-            if (fields && fields.length === 1) {
-                const field = index.fields[0];
-
-                res.line('indexes.add(new ' + res.importClass('org.apache.ignite.cache.QueryIndex') +
-                    '("' + field.name + '", ' +
-                    res.importClass('org.apache.ignite.cache.QueryIndexType') + '.' + index.indexType + ', ' +
-                    field.direction + ', "' + index.name + '"));');
-            }
-            else {
-                res.needEmptyLine = true;
-
-                $generatorJava.declareVariable(res, 'index', 'org.apache.ignite.cache.QueryIndex');
-
-                $generatorJava.property(res, 'index', index, 'name');
-                $generatorJava.enumProperty(res, 'index', index, 'indexType', 'org.apache.ignite.cache.QueryIndexType');
-
-                res.needEmptyLine = true;
-
-                if (fields && fields.length > 0) {
-                    $generatorJava.declareVariable(res, 'indFlds', 'java.util.LinkedHashMap', 'java.util.LinkedHashMap', 'String', 'Boolean');
-
-                    _.forEach(fields, function(field) {
-                        res.line('indFlds.put("' + field.name + '", ' + field.direction + ');');
-                    });
-
-                    res.needEmptyLine = true;
-
-                    res.line('index.setFields(indFlds);');
-
-                    res.needEmptyLine = true;
-                }
-
-                res.line('indexes.add(index);');
-            }
-        });
-
-        res.needEmptyLine = true;
-
-        res.line('qryMeta.setIndexes(indexes);');
-
-        res.needEmptyLine = true;
-    }
-};
-
-// Generate domain model db fields.
-$generatorJava.domainModelDatabaseFields = function(res, domain, fieldProperty) {
-    const dbFields = domain[fieldProperty];
-
-    if (dbFields && dbFields.length > 0) {
-        res.needEmptyLine = true;
-
-        res.importClass('java.sql.Types');
-
-        res.startBlock('jdbcType.' + $generatorCommon.toJavaName('set', fieldProperty) + '(');
-
-        const lastIx = dbFields.length - 1;
-
-        res.importClass('org.apache.ignite.cache.store.jdbc.JdbcTypeField');
-
-        _.forEach(dbFields, function(field, ix) {
-            res.line('new JdbcTypeField(' +
-                'Types.' + field.databaseFieldType + ', ' + '"' + field.databaseFieldName + '", ' +
-                res.importClass(field.javaFieldType) + '.class, ' + '"' + field.javaFieldName + '"' + ')' + (ix < lastIx ? ',' : ''));
-        });
-
-        res.endBlock(');');
-
-        res.needEmptyLine = true;
-    }
-};
-
-// Generate domain model general group.
-$generatorJava.domainModelGeneral = function(domain, res) {
-    if (!res)
-        res = $generatorCommon.builder();
-
-    switch ($generatorCommon.domainQueryMetadata(domain)) {
-        case 'Annotations':
-            if ($generatorCommon.isDefinedAndNotEmpty(domain.keyType) || $generatorCommon.isDefinedAndNotEmpty(domain.valueType)) {
-                const types = [];
-
-                if ($generatorCommon.isDefinedAndNotEmpty(domain.keyType))
-                    types.push($generatorJava.toJavaCode(res.importClass(domain.keyType), 'class'));
-                else
-                    types.push('???');
-
-                if ($generatorCommon.isDefinedAndNotEmpty(domain.valueType))
-                    types.push($generatorJava.toJavaCode(res.importClass(domain.valueType), 'class'));
-                else
-                    types.push('???');
-
-                if ($generatorCommon.isDefinedAndNotEmpty(types))
-                    $generatorJava.fxVarArgs(res, 'cache.setIndexedTypes', false, types);
-            }
-
-            break;
-
-        case 'Configuration':
-            $generatorJava.classNameProperty(res, 'jdbcTypes', domain, 'keyType');
-            $generatorJava.property(res, 'jdbcTypes', domain, 'valueType');
-
-            if ($generatorCommon.isDefinedAndNotEmpty(domain.fields)) {
-                res.needEmptyLine = true;
-
-                $generatorJava.classNameProperty(res, 'qryMeta', domain, 'keyType');
-                $generatorJava.property(res, 'qryMeta', domain, 'valueType');
-            }
-
-            break;
-
-        default:
-    }
-
-    res.needEmptyLine = true;
-
-    return res;
-};
-
-// Generate domain model for query group.
-$generatorJava.domainModelQuery = function(domain, res) {
-    if (!res)
-        res = $generatorCommon.builder();
-
-    if ($generatorCommon.domainQueryMetadata(domain) === 'Configuration') {
-        $generatorJava.domainModelQueryFields(res, domain);
-        $generatorJava.domainModelQueryAliases(res, domain);
-        $generatorJava.domainModelQueryIndexes(res, domain);
-
-        res.needEmptyLine = true;
-    }
-
-    return res;
-};
-
-// Generate domain model for store group.
-$generatorJava.domainStore = function(domain, withTypes, res) {
-    if (!res)
-        res = $generatorCommon.builder();
-
-    $generatorJava.property(res, 'jdbcType', domain, 'databaseSchema');
-    $generatorJava.property(res, 'jdbcType', domain, 'databaseTable');
-
-    if (withTypes) {
-        $generatorJava.classNameProperty(res, 'jdbcType', domain, 'keyType');
-        $generatorJava.property(res, 'jdbcType', domain, 'valueType');
-    }
-
-    $generatorJava.domainModelDatabaseFields(res, domain, 'keyFields');
-    $generatorJava.domainModelDatabaseFields(res, domain, 'valueFields');
-
-    res.needEmptyLine = true;
-
-    return res;
-};
-
-// Generate domain model configs.
-$generatorJava.cacheDomains = function(domains, varName, res) {
-    if (!res)
-        res = $generatorCommon.builder();
-
-    const domainConfigs = _.filter(domains, function(domain) {
-        return $generatorCommon.domainQueryMetadata(domain) === 'Configuration' &&
-            $generatorCommon.isDefinedAndNotEmpty(domain.fields);
-    });
-
-    // Generate domain model configs.
-    if ($generatorCommon.isDefinedAndNotEmpty(domainConfigs)) {
-        $generatorJava.declareVariable(res, 'queryEntities', 'java.util.Collection', 'java.util.ArrayList', 'org.apache.ignite.cache.QueryEntity');
-
-        _.forEach(domainConfigs, function(domain) {
-            if ($generatorCommon.isDefinedAndNotEmpty(domain.fields))
-                res.line('queryEntities.add(queryEntity' + $generatorJava.extractType(domain.valueType) + '());');
-        });
-
-        res.needEmptyLine = true;
-
-        res.line(varName + '.setQueryEntities(queryEntities);');
-
-        res.needEmptyLine = true;
-    }
-
-    return res;
-};
-
-// Generate cache configs.
-$generatorJava.cache = function(cache, varName, res) {
-    if (!res)
-        res = $generatorCommon.builder();
-
-    $generatorJava.cacheGeneral(cache, varName, res);
-    $generatorJava.cacheMemory(cache, varName, res);
-    $generatorJava.cacheQuery(cache, varName, res);
-    $generatorJava.cacheStore(cache, cache.domains, varName, res);
-    $generatorJava.cacheConcurrency(cache, varName, res);
-    $generatorJava.cacheRebalance(cache, varName, res);
-    $generatorJava.cacheServerNearCache(cache, varName, res);
-    $generatorJava.cacheStatistics(cache, varName, res);
-    $generatorJava.cacheDomains(cache.domains, varName, res);
-};
-
-// Generation of cache domain model in separate methods.
-$generatorJava.clusterDomains = function(caches, res) {
-    const domains = [];
-
-    const typeVarName = 'jdbcType';
-    const metaVarName = 'qryMeta';
-
-    _.forEach(caches, function(cache) {
-        _.forEach(cache.domains, function(domain) {
-            if (_.isNil(_.find(domains, function(m) {
-                return m === domain.valueType;
-            }))) {
-                $generatorJava.resetVariables(res);
-
-                const type = $generatorJava.extractType(domain.valueType);
-
-                if ($generatorCommon.isDefinedAndNotEmpty(domain.databaseTable)) {
-                    res.line('/**');
-                    res.line(' * Create JDBC type for ' + type + '.');
-                    res.line(' *');
-                    res.line(' * @param cacheName Cache name.');
-                    res.line(' * @return Configured JDBC type.');
-                    res.line(' */');
-                    res.startBlock('private static JdbcType jdbcType' + type + '(String cacheName) {');
-
-                    $generatorJava.declareVariable(res, typeVarName, 'org.apache.ignite.cache.store.jdbc.JdbcType');
-
-                    res.needEmptyLine = true;
-
-                    res.line(typeVarName + '.setCacheName(cacheName);');
-
-                    $generatorJava.domainStore(domain, true, res);
-
-                    res.needEmptyLine = true;
-
-                    res.line('return ' + typeVarName + ';');
-                    res.endBlock('}');
-
-                    res.needEmptyLine = true;
-                }
-
-                if ($generatorCommon.domainQueryMetadata(domain) === 'Configuration' &&
-                    $generatorCommon.isDefinedAndNotEmpty(domain.fields)) {
-                    res.line('/**');
-                    res.line(' * Create SQL Query descriptor for ' + type + '.');
-                    res.line(' *');
-                    res.line(' * @return Configured query entity.');
-                    res.line(' */');
-                    res.startBlock('private static QueryEntity queryEntity' + type + '() {');
-
-                    $generatorJava.declareVariable(res, metaVarName, 'org.apache.ignite.cache.QueryEntity');
-
-                    $generatorJava.classNameProperty(res, metaVarName, domain, 'keyType');
-                    $generatorJava.property(res, metaVarName, domain, 'valueType');
-
-                    res.needEmptyLine = true;
-
-                    $generatorJava.domainModelQuery(domain, res);
-
-                    res.emptyLineIfNeeded();
-                    res.line('return ' + metaVarName + ';');
-
-                    res.needEmptyLine = true;
-
-                    res.endBlock('}');
-                }
-
-                domains.push(domain.valueType);
-            }
-        });
-    });
-};
-
-/**
- * @param prefix Variable prefix.
- * @param obj Object to process.
- * @param names Known names to generate next unique name.
- */
-$generatorJava.nextVariableName = function(prefix, obj, names) {
-    let nextName = $generatorCommon.toJavaName(prefix, obj.name);
-
-    let ix = 0;
-
-    const checkNextName = (name) => name === nextName + (ix === 0 ? '' : '_' + ix);
-
-    while (_.find(names, (name) => checkNextName(name)))
-        ix++;
-
-    if (ix > 0)
-        nextName = nextName + '_' + ix;
-
-    return nextName;
-};
-
-// Generate cluster caches.
-$generatorJava.clusterCaches = function(caches, igfss, isSrvCfg, res) {
-    function clusterCache(cache, names) {
-        res.emptyLineIfNeeded();
-
-        const cacheName = $generatorJava.nextVariableName('cache', cache, names);
-
-        $generatorJava.resetVariables(res);
-
-        const hasDatasource = $generatorCommon.cacheHasDatasource(cache);
-
-        res.line('/**');
-        res.line(' * Create configuration for cache "' + cache.name + '".');
-        res.line(' *');
-        res.line(' * @return Configured cache.');
-
-        if (hasDatasource)
-            res.line(' * @throws Exception if failed to create cache configuration.');
-
-        res.line(' */');
-        res.startBlock('public static CacheConfiguration ' + cacheName + '()' + (hasDatasource ? ' throws Exception' : '') + ' {');
-
-        $generatorJava.declareVariable(res, cacheName, 'org.apache.ignite.configuration.CacheConfiguration');
-
-        $generatorJava.cache(cache, cacheName, res);
-
-        res.line('return ' + cacheName + ';');
-        res.endBlock('}');
-
-        names.push(cacheName);
-
-        res.needEmptyLine = true;
-    }
-
-    if (!res)
-        res = $generatorCommon.builder();
-
-    const names = [];
-
-    if ($generatorCommon.isDefinedAndNotEmpty(caches)) {
-        res.emptyLineIfNeeded();
-
-        _.forEach(caches, function(cache) {
-            clusterCache(cache, names);
-        });
-
-        res.needEmptyLine = true;
-    }
-
-    if (isSrvCfg && $generatorCommon.isDefinedAndNotEmpty(igfss)) {
-        res.emptyLineIfNeeded();
-
-        _.forEach(igfss, function(igfs) {
-            clusterCache($generatorCommon.igfsDataCache(igfs), names);
-            clusterCache($generatorCommon.igfsMetaCache(igfs), names);
-        });
-
-        res.needEmptyLine = true;
-    }
-
-    return res;
-};
-
-// Generate cluster caches.
-$generatorJava.clusterCacheUse = function(caches, igfss, res) {
-    function clusterCacheInvoke(cache, names) {
-        names.push($generatorJava.nextVariableName('cache', cache, names));
-    }
-
-    if (!res)
-        res = $generatorCommon.builder();
-
-    const cacheNames = [];
-
-    _.forEach(caches, function(cache) {
-        clusterCacheInvoke(cache, cacheNames);
-    });
-
-    const igfsNames = [];
-
-    _.forEach(igfss, function(igfs) {
-        clusterCacheInvoke($generatorCommon.igfsDataCache(igfs), igfsNames);
-        clusterCacheInvoke($generatorCommon.igfsMetaCache(igfs), igfsNames);
-    });
-
-    const allCacheNames = cacheNames.concat(igfsNames);
-
-    if (allCacheNames.length) {
-        res.line('cfg.setCacheConfiguration(' + allCacheNames.join('(), ') + '());');
-
-        res.needEmptyLine = true;
-    }
-
-    return res;
-};
-
-// Get class name from fully specified class path.
-$generatorJava.extractType = function(fullType) {
-    return fullType.substring(fullType.lastIndexOf('.') + 1);
-};
-
-/**
- * Generate java class code.
- *
- * @param domain Domain model object.
- * @param key If 'true' then key class should be generated.
- * @param pkg Package name.
- * @param useConstructor If 'true' then empty and full constructors should be generated.
- * @param includeKeyFields If 'true' then include key fields into value POJO.
- * @param res Resulting output with generated code.
- */
-$generatorJava.javaClassCode = function(domain, key, pkg, useConstructor, includeKeyFields, res) {
-    if (!res)
-        res = $generatorCommon.builder();
-
-    const type = $generatorJava.extractType(key ? domain.keyType : domain.valueType);
-
-    // Class comment.
-    res.line('/**');
-    res.line(' * ' + type + ' definition.');
-    res.line(' *');
-    res.line(' * ' + $generatorCommon.mainComment());
-    res.line(' */');
-
-    res.startBlock('public class ' + type + ' implements ' + res.importClass('java.io.Serializable') + ' {');
-
-    res.line('/** */');
-    res.line('private static final long serialVersionUID = 0L;');
-    res.needEmptyLine = true;
-
-    const allFields = (key || includeKeyFields) ? domain.keyFields.slice() : [];
-
-    if (!key) {
-        _.forEach(domain.valueFields, (valFld) => {
-            if (_.findIndex(allFields, (fld) => fld.javaFieldName === valFld.javaFieldName) < 0)
-                allFields.push(valFld);
-        });
-    }
-
-    // Generate allFields declaration.
-    _.forEach(allFields, function(field) {
-        const fldName = field.javaFieldName;
-
-        res.line('/** Value for ' + fldName + '. */');
-
-        res.line('private ' + res.importClass(field.javaFieldType) + ' ' + fldName + ';');
-
-        res.needEmptyLine = true;
-    });
-
-    // Generate constructors.
-    if (useConstructor) {
-        res.line('/**');
-        res.line(' * Empty constructor.');
-        res.line(' */');
-        res.startBlock('public ' + type + '() {');
-        res.line('// No-op.');
-        res.endBlock('}');
-
-        res.needEmptyLine = true;
-
-        res.line('/**');
-        res.line(' * Full constructor.');
-        res.line(' */');
-        res.startBlock('public ' + type + '(');
-
-        _.forEach(allFields, function(field, idx) {
-            res.line(res.importClass(field.javaFieldType) + ' ' + field.javaFieldName + (idx < allFields.length - 1 ? ',' : ''));
-        });
-
-        res.endBlock(') {');
-
-        res.startBlock();
-
-        _.forEach(allFields, (field) => res.line('this.' + field.javaFieldName + ' = ' + field.javaFieldName + ';'));
-
-        res.endBlock('}');
-
-        res.needEmptyLine = true;
-    }
-
-    // Generate getters and setters methods.
-    _.forEach(allFields, function(field) {
-        const fldName = field.javaFieldName;
-
-        const fldType = res.importClass(field.javaFieldType);
-
-        res.line('/**');
-        res.line(' * Gets ' + fldName + '.');
-        res.line(' *');
-        res.line(' * @return Value for ' + fldName + '.');
-        res.line(' */');
-        res.startBlock('public ' + fldType + ' ' + $generatorCommon.toJavaName('get', fldName) + '() {');
-        res.line('return ' + fldName + ';');
-        res.endBlock('}');
-
-        res.needEmptyLine = true;
-
-        res.line('/**');
-        res.line(' * Sets ' + fldName + '.');
-        res.line(' *');
-        res.line(' * @param ' + fldName + ' New value for ' + fldName + '.');
-        res.line(' */');
-        res.startBlock('public void ' + $generatorCommon.toJavaName('set', fldName) + '(' + fldType + ' ' + fldName + ') {');
-        res.line('this.' + fldName + ' = ' + fldName + ';');
-        res.endBlock('}');
-
-        res.needEmptyLine = true;
-    });
-
-    // Generate equals() method.
-    res.line('/** {@inheritDoc} */');
-    res.startBlock('@Override public boolean equals(Object o) {');
-    res.startBlock('if (this == o)');
-    res.line('return true;');
-    res.endBlock();
-    res.append('');
-
-    res.startBlock('if (!(o instanceof ' + type + '))');
-    res.line('return false;');
-    res.endBlock();
-
-    res.needEmptyLine = true;
-
-    res.line(type + ' that = (' + type + ')o;');
-
-    _.forEach(allFields, function(field) {
-        res.needEmptyLine = true;
-
-        const javaName = field.javaFieldName;
-        const javaType = field.javaFieldType;
-
-        if ($generatorCommon.JavaTypes.isJavaPrimitive(javaType)) {
-            if (javaType === 'float')
-                res.startBlock('if (Float.compare(' + javaName + ', that.' + javaName + ') != 0)');
-            else if (javaType === 'double')
-                res.startBlock('if (Double.compare(' + javaName + ', that.' + javaName + ') != 0)');
-            else
-                res.startBlock('if (' + javaName + ' != that.' + javaName + ')');
-        }
-        else
-            res.startBlock('if (' + javaName + ' != null ? !' + javaName + '.equals(that.' + javaName + ') : that.' + javaName + ' != null)');
-
-        res.line('return false;');
-        res.endBlock();
-    });
-
-    res.needEmptyLine = true;
-
-    res.line('return true;');
-    res.endBlock('}');
-
-    res.needEmpt

<TRUNCATED>

[05/52] ignite git commit: Web Console beta-3.

Posted by ak...@apache.org.
http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/src/main/js/serve/browser.js
----------------------------------------------------------------------
diff --git a/modules/web-console/src/main/js/serve/browser.js b/modules/web-console/src/main/js/serve/browser.js
deleted file mode 100644
index 8a6d33e..0000000
--- a/modules/web-console/src/main/js/serve/browser.js
+++ /dev/null
@@ -1,378 +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.
- */
-
-'use strict';
-
-// Fire me up!
-
-/**
- * Module interaction with browsers.
- */
-module.exports = {
-    implements: 'browser-manager',
-    inject: ['require(lodash)', 'require(socket.io)', 'agent-manager', 'configure']
-};
-
-module.exports.factory = (_, socketio, agentMgr, configure) => {
-    const _errorToJson = (err) => {
-        return {
-            message: err.message || err,
-            code: err.code || 1
-        };
-    };
-
-    return {
-        attach: (server) => {
-            const io = socketio(server);
-
-            configure.socketio(io);
-
-            io.sockets.on('connection', (socket) => {
-                const user = socket.request.user;
-
-                const demo = socket.request._query.IgniteDemoMode === 'true';
-
-                const accountId = () => user._id;
-
-                // Return available drivers to browser.
-                socket.on('schemaImport:drivers', (cb) => {
-                    agentMgr.findAgent(accountId())
-                        .then((agent) => agent.availableDrivers())
-                        .then((drivers) => cb(null, drivers))
-                        .catch((err) => cb(_errorToJson(err)));
-                });
-
-                // Return schemas from database to browser.
-                socket.on('schemaImport:schemas', (preset, cb) => {
-                    agentMgr.findAgent(accountId())
-                        .then((agent) => {
-                            const jdbcInfo = {user: preset.user, password: preset.password};
-
-                            return agent.metadataSchemas(preset.jdbcDriverJar, preset.jdbcDriverClass, preset.jdbcUrl, jdbcInfo);
-                        })
-                        .then((schemas) => cb(null, schemas))
-                        .catch((err) => cb(_errorToJson(err)));
-                });
-
-                // Return tables from database to browser.
-                socket.on('schemaImport:tables', (preset, cb) => {
-                    agentMgr.findAgent(accountId())
-                        .then((agent) => {
-                            const jdbcInfo = {user: preset.user, password: preset.password};
-
-                            return agent.metadataTables(preset.jdbcDriverJar, preset.jdbcDriverClass, preset.jdbcUrl, jdbcInfo,
-                                preset.schemas, preset.tablesOnly);
-                        })
-                        .then((tables) => cb(null, tables))
-                        .catch((err) => cb(_errorToJson(err)));
-                });
-
-                // Return topology command result from grid to browser.
-                socket.on('node:topology', (attr, mtr, cb) => {
-                    agentMgr.findAgent(accountId())
-                        .then((agent) => agent.topology(demo, attr, mtr))
-                        .then((clusters) => cb(null, clusters))
-                        .catch((err) => cb(_errorToJson(err)));
-                });
-
-                // Close query on node.
-                socket.on('node:query:close', (queryId, cb) => {
-                    agentMgr.findAgent(accountId())
-                        .then((agent) => agent.queryClose(demo, queryId))
-                        .then(() => cb())
-                        .catch((err) => cb(_errorToJson(err)));
-                });
-
-                // Execute query on node and return first page to browser.
-                socket.on('node:query', (cacheName, pageSize, query, cb) => {
-                    agentMgr.findAgent(accountId())
-                        .then((agent) => {
-                            if (query === null)
-                                return agent.scan(demo, cacheName, pageSize);
-
-                            return agent.fieldsQuery(demo, cacheName, query, pageSize);
-                        })
-                        .then((res) => cb(null, res))
-                        .catch((err) => cb(_errorToJson(err)));
-                });
-
-                // Fetch next page for query and return result to browser.
-                socket.on('node:query:fetch', (queryId, pageSize, cb) => {
-                    agentMgr.findAgent(accountId())
-                        .then((agent) => agent.queryFetch(demo, queryId, pageSize))
-                        .then((res) => cb(null, res))
-                        .catch((err) => cb(_errorToJson(err)));
-                });
-
-                // Execute query on node and return full result to browser.
-                socket.on('node:query:getAll', (cacheName, query, cb) => {
-                    // Set page size for query.
-                    const pageSize = 1024;
-
-                    agentMgr.findAgent(accountId())
-                        .then((agent) => {
-                            const firstPage = query === null ? agent.scan(demo, cacheName, pageSize)
-                                : agent.fieldsQuery(demo, cacheName, query, pageSize);
-
-                            const fetchResult = (acc) => {
-                                if (acc.last)
-                                    return acc;
-
-                                return agent.queryFetch(demo, acc.queryId, pageSize)
-                                    .then((res) => {
-                                        acc.items = acc.items.concat(res.items);
-
-                                        acc.last = res.last;
-
-                                        return fetchResult(acc);
-                                    });
-                            };
-
-                            return firstPage
-                                .then(fetchResult);
-                        })
-                        .then((res) => cb(null, res))
-                        .catch((err) => cb(_errorToJson(err)));
-                });
-
-                // Return cache metadata from all nodes in grid.
-                socket.on('node:cache:metadata', (cacheName, cb) => {
-                    agentMgr.findAgent(accountId())
-                        .then((agent) => agent.metadata(demo, cacheName))
-                        .then((caches) => {
-                            let types = [];
-
-                            const _compact = (className) => {
-                                return className.replace('java.lang.', '').replace('java.util.', '').replace('java.sql.', '');
-                            };
-
-                            const _typeMapper = (meta, typeName) => {
-                                const maskedName = _.isEmpty(meta.cacheName) ? '<default>' : meta.cacheName;
-
-                                let fields = meta.fields[typeName];
-
-                                let columns = [];
-
-                                for (const fieldName in fields) {
-                                    if (fields.hasOwnProperty(fieldName)) {
-                                        const fieldClass = _compact(fields[fieldName]);
-
-                                        columns.push({
-                                            type: 'field',
-                                            name: fieldName,
-                                            clazz: fieldClass,
-                                            system: fieldName === '_KEY' || fieldName === '_VAL',
-                                            cacheName: meta.cacheName,
-                                            typeName,
-                                            maskedName
-                                        });
-                                    }
-                                }
-
-                                const indexes = [];
-
-                                for (const index of meta.indexes[typeName]) {
-                                    fields = [];
-
-                                    for (const field of index.fields) {
-                                        fields.push({
-                                            type: 'index-field',
-                                            name: field,
-                                            order: index.descendings.indexOf(field) < 0,
-                                            unique: index.unique,
-                                            cacheName: meta.cacheName,
-                                            typeName,
-                                            maskedName
-                                        });
-                                    }
-
-                                    if (fields.length > 0) {
-                                        indexes.push({
-                                            type: 'index',
-                                            name: index.name,
-                                            children: fields,
-                                            cacheName: meta.cacheName,
-                                            typeName,
-                                            maskedName
-                                        });
-                                    }
-                                }
-
-                                columns = _.sortBy(columns, 'name');
-
-                                if (!_.isEmpty(indexes)) {
-                                    columns = columns.concat({
-                                        type: 'indexes',
-                                        name: 'Indexes',
-                                        cacheName: meta.cacheName,
-                                        typeName,
-                                        maskedName,
-                                        children: indexes
-                                    });
-                                }
-
-                                return {
-                                    type: 'type',
-                                    cacheName: meta.cacheName || '',
-                                    typeName,
-                                    maskedName,
-                                    children: columns
-                                };
-                            };
-
-                            for (const meta of caches) {
-                                const cacheTypes = meta.types.map(_typeMapper.bind(null, meta));
-
-                                if (!_.isEmpty(cacheTypes))
-                                    types = types.concat(cacheTypes);
-                            }
-
-                            return cb(null, types);
-                        })
-                        .catch((err) => cb(_errorToJson(err)));
-                });
-
-                // Fetch next page for query and return result to browser.
-                socket.on('node:visor:collect', (evtOrderKey, evtThrottleCntrKey, cb) => {
-                    agentMgr.findAgent(accountId())
-                        .then((agent) => agent.collect(demo, evtOrderKey, evtThrottleCntrKey))
-                        .then((data) => {
-                            if (data.finished)
-                                return cb(null, data.result);
-
-                            cb(_errorToJson(data.error));
-                        })
-                        .catch((err) => cb(_errorToJson(err)));
-                });
-
-                // Swap backups specified caches on specified node and return result to browser.
-                socket.on('node:cache:swap:backups', (nid, cacheNames, cb) => {
-                    agentMgr.findAgent(accountId())
-                        .then((agent) => agent.cacheSwapBackups(demo, nid, cacheNames))
-                        .then((data) => {
-                            if (data.finished)
-                                return cb(null, data.result);
-
-                            cb(_errorToJson(data.error));
-                        })
-                        .catch((err) => cb(_errorToJson(err)));
-                });
-
-                // Reset metrics specified cache on specified node and return result to browser.
-                socket.on('node:cache:reset:metrics', (nid, cacheName, cb) => {
-                    agentMgr.findAgent(accountId())
-                        .then((agent) => agent.cacheResetMetrics(demo, nid, cacheName))
-                        .then((data) => {
-                            if (data.finished)
-                                return cb(null, data.result);
-
-                            cb(_errorToJson(data.error));
-                        })
-                        .catch((err) => cb(_errorToJson(err)));
-                });
-
-                // Clear specified cache on specified node and return result to browser.
-                socket.on('node:cache:clear', (nid, cacheName, cb) => {
-                    agentMgr.findAgent(accountId())
-                        .then((agent) => agent.cacheClear(demo, nid, cacheName))
-                        .then((data) => {
-                            if (data.finished)
-                                return cb(null, data.result);
-
-                            cb(_errorToJson(data.error));
-                        })
-                        .catch((err) => cb(_errorToJson(err)));
-                });
-
-                // Start specified cache and return result to browser.
-                socket.on('node:cache:start', (nids, near, cacheName, cfg, cb) => {
-                    agentMgr.findAgent(accountId())
-                        .then((agent) => agent.cacheStart(demo, nids, near, cacheName, cfg))
-                        .then((data) => {
-                            if (data.finished)
-                                return cb(null, data.result);
-
-                            cb(_errorToJson(data.error));
-                        })
-                        .catch((err) => cb(_errorToJson(err)));
-                });
-
-                // Stop specified cache on specified node and return result to browser.
-                socket.on('node:cache:stop', (nid, cacheName, cb) => {
-                    agentMgr.findAgent(accountId())
-                        .then((agent) => agent.cacheStop(demo, nid, cacheName))
-                        .then((data) => {
-                            if (data.finished)
-                                return cb(null, data.result);
-
-                            cb(_errorToJson(data.error));
-                        })
-                        .catch((err) => cb(_errorToJson(err)));
-                });
-
-
-                // Ping node and return result to browser.
-                socket.on('node:ping', (taskNid, nid, cb) => {
-                    agentMgr.findAgent(accountId())
-                        .then((agent) => agent.ping(demo, taskNid, nid))
-                        .then((data) => {
-                            if (data.finished)
-                                return cb(null, data.result);
-
-                            cb(_errorToJson(data.error));
-                        })
-                        .catch((err) => cb(_errorToJson(err)));
-                });
-
-                // GC node and return result to browser.
-                socket.on('node:gc', (nids, cb) => {
-                    agentMgr.findAgent(accountId())
-                        .then((agent) => agent.gc(demo, nids))
-                        .then((data) => {
-                            if (data.finished)
-                                return cb(null, data.result);
-
-                            cb(_errorToJson(data.error));
-                        })
-                        .catch((err) => cb(_errorToJson(err)));
-                });
-
-                // GC node and return result to browser.
-                socket.on('node:thread:dump', (nid, cb) => {
-                    agentMgr.findAgent(accountId())
-                        .then((agent) => agent.threadDump(demo, nid))
-                        .then((data) => {
-                            if (data.finished)
-                                return cb(null, data.result);
-
-                            cb(_errorToJson(data.error));
-                        })
-                        .catch((err) => cb(_errorToJson(err)));
-                });
-
-                const count = agentMgr.addAgentListener(user._id, socket);
-
-                socket.emit('agent:count', {count});
-            });
-
-            // Handle browser disconnect event.
-            io.sockets.on('disconnect', (socket) =>
-                agentMgr.removeAgentListener(socket.client.request.user._id, socket)
-            );
-        }
-    };
-};

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/src/main/js/serve/config/settings.json.sample
----------------------------------------------------------------------
diff --git a/modules/web-console/src/main/js/serve/config/settings.json.sample b/modules/web-console/src/main/js/serve/config/settings.json.sample
deleted file mode 100644
index 94dd9f7..0000000
--- a/modules/web-console/src/main/js/serve/config/settings.json.sample
+++ /dev/null
@@ -1,26 +0,0 @@
-{
-    "server": {
-        "port": 3000,
-        "ssl": false,
-        "key": "serve/keys/test.key",
-        "cert": "serve/keys/test.crt",
-        "keyPassphrase": "password"
-    },
-    "mongoDB": {
-        "url": "mongodb://localhost/console"
-    },
-    "agent-server": {
-        "port": 3001,
-        "ssl": false,
-        "key": "serve/keys/test.key",
-        "cert": "serve/keys/test.crt",
-        "keyPassphrase": "password"
-    },
-    "smtp": {
-        "service": "",
-        "username": "Apache Ignite Web Console",
-        "sign": "Kind regards,<br>Apache Ignite Team",
-        "email": "",
-        "password": ""
-    }
-}

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/src/main/js/serve/configure.js
----------------------------------------------------------------------
diff --git a/modules/web-console/src/main/js/serve/configure.js b/modules/web-console/src/main/js/serve/configure.js
deleted file mode 100644
index 9671d66..0000000
--- a/modules/web-console/src/main/js/serve/configure.js
+++ /dev/null
@@ -1,84 +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.
- */
-
-'use strict';
-
-// Fire me up!
-
-/**
- * Module for configuration express and websocket server.
- */
-module.exports = {
-    implements: 'configure',
-    inject: ['require(morgan)', 'require(cookie-parser)', 'require(body-parser)',
-        'require(express-session)', 'require(connect-mongo)', 'require(passport)', 'require(passport.socketio)', 'settings', 'mongo']
-};
-
-module.exports.factory = function(logger, cookieParser, bodyParser, session, connectMongo, passport, passportSocketIo, settings, mongo) {
-    const _sessionStore = new (connectMongo(session))({mongooseConnection: mongo.connection});
-
-    return {
-        express: (app) => {
-            app.use(logger('dev', {
-                skip: (req, res) => res.statusCode < 400
-            }));
-
-            app.use(cookieParser(settings.sessionSecret));
-
-            app.use(bodyParser.json({limit: '50mb'}));
-            app.use(bodyParser.urlencoded({limit: '50mb', extended: true}));
-
-            app.use(session({
-                secret: settings.sessionSecret,
-                resave: false,
-                saveUninitialized: true,
-                unset: 'destroy',
-                cookie: {
-                    expires: new Date(Date.now() + settings.cookieTTL),
-                    maxAge: settings.cookieTTL
-                },
-                store: _sessionStore
-            }));
-
-            app.use(passport.initialize());
-            app.use(passport.session());
-
-            passport.serializeUser(mongo.Account.serializeUser());
-            passport.deserializeUser(mongo.Account.deserializeUser());
-
-            passport.use(mongo.Account.createStrategy());
-        },
-        socketio: (io) => {
-            const _onAuthorizeSuccess = (data, accept) => {
-                accept(null, true);
-            };
-
-            const _onAuthorizeFail = (data, message, error, accept) => {
-                accept(null, false);
-            };
-
-            io.use(passportSocketIo.authorize({
-                cookieParser,
-                key: 'connect.sid', // the name of the cookie where express/connect stores its session_id
-                secret: settings.sessionSecret, // the session_secret to parse the cookie
-                store: _sessionStore, // we NEED to use a sessionstore. no memorystore please
-                success: _onAuthorizeSuccess, // *optional* callback on success - read more below
-                fail: _onAuthorizeFail // *optional* callback on fail/error - read more below
-            }));
-        }
-    };
-};

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/src/main/js/serve/mail.js
----------------------------------------------------------------------
diff --git a/modules/web-console/src/main/js/serve/mail.js b/modules/web-console/src/main/js/serve/mail.js
deleted file mode 100644
index 2c67276..0000000
--- a/modules/web-console/src/main/js/serve/mail.js
+++ /dev/null
@@ -1,75 +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.
- */
-
-'use strict';
-
-// Fire me up!
-
-/**
- * Module for send email.
- */
-module.exports = {
-    implements: 'mail',
-    inject: ['require(nodemailer)', 'settings']
-};
-
-module.exports.factory = function(nodemailer, settings) {
-    return {
-        /**
-         * Send mail to user.
-         *
-         * @param {Account} user
-         * @param {String} subject
-         * @param {String} html
-         * @param {String} sendErr
-         * @throws {Error}
-         * @return {Promise}
-         */
-        send: (user, subject, html, sendErr) => {
-            const transporter = {
-                service: settings.smtp.service,
-                auth: {
-                    user: settings.smtp.email,
-                    pass: settings.smtp.password
-                }
-            };
-
-            if (transporter.service === '' || transporter.auth.user === '' || transporter.auth.pass === '')
-                throw new Error('Failed to send email. SMTP server is not configured. Please ask webmaster to setup SMTP server!');
-
-            const mailer = nodemailer.createTransport(transporter);
-
-            const sign = settings.smtp.sign ? `<br><br>--------------<br>${settings.smtp.sign}<br>` : '';
-
-            const mail = {
-                from: settings.smtp.address(settings.smtp.username, settings.smtp.email),
-                to: settings.smtp.address(`${user.firstName} ${user.lastName}`, user.email),
-                subject,
-                html: html + sign
-            };
-
-            return new Promise((resolve, reject) => {
-                mailer.sendMail(mail, (err) => {
-                    if (err)
-                        return reject(sendErr ? new Error(sendErr) : err);
-
-                    resolve(user);
-                });
-            });
-        }
-    };
-};

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/src/main/js/serve/mongo.js
----------------------------------------------------------------------
diff --git a/modules/web-console/src/main/js/serve/mongo.js b/modules/web-console/src/main/js/serve/mongo.js
deleted file mode 100644
index 8fb0a20..0000000
--- a/modules/web-console/src/main/js/serve/mongo.js
+++ /dev/null
@@ -1,676 +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.
- */
-
-'use strict';
-
-// Fire me up!
-
-/**
- * Module mongo schema.
- */
-module.exports = {
-    implements: 'mongo',
-    inject: ['require(mongoose-deep-populate)', 'require(passport-local-mongoose)', 'settings', 'ignite_modules/mongo:*']
-};
-
-module.exports.factory = function(deepPopulatePlugin, passportMongo, settings, pluginMongo) {
-    const mongoose = require('mongoose');
-
-    // Use native promises
-    mongoose.Promise = global.Promise;
-
-    const deepPopulate = deepPopulatePlugin(mongoose);
-
-    // Connect to mongoDB database.
-    mongoose.connect(settings.mongoUrl, {server: {poolSize: 4}});
-
-    const Schema = mongoose.Schema;
-    const ObjectId = mongoose.Schema.Types.ObjectId;
-    const result = { connection: mongoose.connection };
-
-    result.ObjectId = ObjectId;
-
-    // Define Account schema.
-    const AccountSchema = new Schema({
-        firstName: String,
-        lastName: String,
-        email: String,
-        company: String,
-        country: String,
-        lastLogin: Date,
-        admin: Boolean,
-        token: String,
-        resetPasswordToken: String
-    });
-
-    // Install passport plugin.
-    AccountSchema.plugin(passportMongo, {
-        usernameField: 'email', limitAttempts: true, lastLoginField: 'lastLogin',
-        usernameLowerCase: true
-    });
-
-    // Configure transformation to JSON.
-    AccountSchema.set('toJSON', {
-        transform: (doc, ret) => {
-            return {
-                _id: ret._id,
-                email: ret.email,
-                firstName: ret.firstName,
-                lastName: ret.lastName,
-                company: ret.company,
-                country: ret.country,
-                admin: ret.admin,
-                token: ret.token,
-                lastLogin: ret.lastLogin
-            };
-        }
-    });
-
-    // Define Account model.
-    result.Account = mongoose.model('Account', AccountSchema);
-
-    // Define Space model.
-    result.Space = mongoose.model('Space', new Schema({
-        name: String,
-        owner: {type: ObjectId, ref: 'Account'},
-        demo: {type: Boolean, default: false},
-        usedBy: [{
-            permission: {type: String, enum: ['VIEW', 'FULL']},
-            account: {type: ObjectId, ref: 'Account'}
-        }]
-    }));
-
-    // Define Domain model schema.
-    const DomainModelSchema = new Schema({
-        space: {type: ObjectId, ref: 'Space', index: true},
-        caches: [{type: ObjectId, ref: 'Cache'}],
-        queryMetadata: {type: String, enum: ['Annotations', 'Configuration']},
-        kind: {type: String, enum: ['query', 'store', 'both']},
-        databaseSchema: String,
-        databaseTable: String,
-        keyType: String,
-        valueType: String,
-        keyFields: [{
-            databaseFieldName: String,
-            databaseFieldType: String,
-            javaFieldName: String,
-            javaFieldType: String
-        }],
-        valueFields: [{
-            databaseFieldName: String,
-            databaseFieldType: String,
-            javaFieldName: String,
-            javaFieldType: String
-        }],
-        fields: [{name: String, className: String}],
-        aliases: [{field: String, alias: String}],
-        indexes: [{
-            name: String,
-            indexType: {type: String, enum: ['SORTED', 'FULLTEXT', 'GEOSPATIAL']},
-            fields: [{name: String, direction: Boolean}]
-        }],
-        demo: Boolean
-    });
-
-    // Define model of Domain models.
-    result.DomainModel = mongoose.model('DomainModel', DomainModelSchema);
-
-    // Define Cache schema.
-    const CacheSchema = new Schema({
-        space: {type: ObjectId, ref: 'Space', index: true},
-        name: String,
-        clusters: [{type: ObjectId, ref: 'Cluster'}],
-        domains: [{type: ObjectId, ref: 'DomainModel'}],
-        cacheMode: {type: String, enum: ['PARTITIONED', 'REPLICATED', 'LOCAL']},
-        atomicityMode: {type: String, enum: ['ATOMIC', 'TRANSACTIONAL']},
-
-        backups: Number,
-        memoryMode: {type: String, enum: ['ONHEAP_TIERED', 'OFFHEAP_TIERED', 'OFFHEAP_VALUES']},
-        offHeapMaxMemory: Number,
-        startSize: Number,
-        swapEnabled: Boolean,
-
-        evictionPolicy: {
-            kind: {type: String, enum: ['LRU', 'FIFO', 'SORTED']},
-            LRU: {
-                batchSize: Number,
-                maxMemorySize: Number,
-                maxSize: Number
-            },
-            FIFO: {
-                batchSize: Number,
-                maxMemorySize: Number,
-                maxSize: Number
-            },
-            SORTED: {
-                batchSize: Number,
-                maxMemorySize: Number,
-                maxSize: Number
-            }
-        },
-
-        rebalanceMode: {type: String, enum: ['SYNC', 'ASYNC', 'NONE']},
-        rebalanceBatchSize: Number,
-        rebalanceBatchesPrefetchCount: Number,
-        rebalanceOrder: Number,
-        rebalanceDelay: Number,
-        rebalanceTimeout: Number,
-        rebalanceThrottle: Number,
-
-        cacheStoreFactory: {
-            kind: {
-                type: String,
-                enum: ['CacheJdbcPojoStoreFactory', 'CacheJdbcBlobStoreFactory', 'CacheHibernateBlobStoreFactory']
-            },
-            CacheJdbcPojoStoreFactory: {
-                dataSourceBean: String,
-                dialect: {
-                    type: String,
-                    enum: ['Generic', 'Oracle', 'DB2', 'SQLServer', 'MySQL', 'PostgreSQL', 'H2']
-                }
-            },
-            CacheJdbcBlobStoreFactory: {
-                connectVia: {type: String, enum: ['URL', 'DataSource']},
-                connectionUrl: String,
-                user: String,
-                dataSourceBean: String,
-                dialect: {
-                    type: String,
-                    enum: ['Generic', 'Oracle', 'DB2', 'SQLServer', 'MySQL', 'PostgreSQL', 'H2']
-                },
-                initSchema: Boolean,
-                createTableQuery: String,
-                loadQuery: String,
-                insertQuery: String,
-                updateQuery: String,
-                deleteQuery: String
-            },
-            CacheHibernateBlobStoreFactory: {
-                hibernateProperties: [String]
-            }
-        },
-        storeKeepBinary: Boolean,
-        loadPreviousValue: Boolean,
-        readThrough: Boolean,
-        writeThrough: Boolean,
-
-        writeBehindEnabled: Boolean,
-        writeBehindBatchSize: Number,
-        writeBehindFlushSize: Number,
-        writeBehindFlushFrequency: Number,
-        writeBehindFlushThreadCount: Number,
-
-        invalidate: Boolean,
-        defaultLockTimeout: Number,
-        atomicWriteOrderMode: {type: String, enum: ['CLOCK', 'PRIMARY']},
-        writeSynchronizationMode: {type: String, enum: ['FULL_SYNC', 'FULL_ASYNC', 'PRIMARY_SYNC']},
-
-        sqlEscapeAll: Boolean,
-        sqlSchema: String,
-        sqlOnheapRowCacheSize: Number,
-        longQueryWarningTimeout: Number,
-        sqlFunctionClasses: [String],
-        snapshotableIndex: Boolean,
-        statisticsEnabled: Boolean,
-        managementEnabled: Boolean,
-        readFromBackup: Boolean,
-        copyOnRead: Boolean,
-        maxConcurrentAsyncOperations: Number,
-        nearCacheEnabled: Boolean,
-        nearConfiguration: {
-            nearStartSize: Number,
-            nearEvictionPolicy: {
-                kind: {type: String, enum: ['LRU', 'FIFO', 'SORTED']},
-                LRU: {
-                    batchSize: Number,
-                    maxMemorySize: Number,
-                    maxSize: Number
-                },
-                FIFO: {
-                    batchSize: Number,
-                    maxMemorySize: Number,
-                    maxSize: Number
-                },
-                SORTED: {
-                    batchSize: Number,
-                    maxMemorySize: Number,
-                    maxSize: Number
-                }
-            }
-        },
-        demo: Boolean
-    });
-
-    // Install deep populate plugin.
-    CacheSchema.plugin(deepPopulate, {
-        whitelist: ['domains']
-    });
-
-    // Define Cache model.
-    result.Cache = mongoose.model('Cache', CacheSchema);
-
-    const IgfsSchema = new Schema({
-        space: {type: ObjectId, ref: 'Space', index: true},
-        name: String,
-        clusters: [{type: ObjectId, ref: 'Cluster'}],
-        affinnityGroupSize: Number,
-        blockSize: Number,
-        streamBufferSize: Number,
-        dataCacheName: String,
-        metaCacheName: String,
-        defaultMode: {type: String, enum: ['PRIMARY', 'PROXY', 'DUAL_SYNC', 'DUAL_ASYNC']},
-        dualModeMaxPendingPutsSize: Number,
-        dualModePutExecutorService: String,
-        dualModePutExecutorServiceShutdown: Boolean,
-        fragmentizerConcurrentFiles: Number,
-        fragmentizerEnabled: Boolean,
-        fragmentizerThrottlingBlockLength: Number,
-        fragmentizerThrottlingDelay: Number,
-        ipcEndpointConfiguration: {
-            type: {type: String, enum: ['SHMEM', 'TCP']},
-            host: String,
-            port: Number,
-            memorySize: Number,
-            tokenDirectoryPath: String
-        },
-        ipcEndpointEnabled: Boolean,
-        maxSpaceSize: Number,
-        maximumTaskRangeLength: Number,
-        managementPort: Number,
-        pathModes: [{path: String, mode: {type: String, enum: ['PRIMARY', 'PROXY', 'DUAL_SYNC', 'DUAL_ASYNC']}}],
-        perNodeBatchSize: Number,
-        perNodeParallelBatchCount: Number,
-        prefetchBlocks: Number,
-        sequentialReadsBeforePrefetch: Number,
-        trashPurgeTimeout: Number,
-        secondaryFileSystemEnabled: Boolean,
-        secondaryFileSystem: {
-            uri: String,
-            cfgPath: String,
-            userName: String
-        },
-        colocateMetadata: Boolean,
-        relaxedConsistency: Boolean
-    });
-
-    // Define IGFS model.
-    result.Igfs = mongoose.model('Igfs', IgfsSchema);
-
-    // Define Cluster schema.
-    const ClusterSchema = new Schema({
-        space: {type: ObjectId, ref: 'Space', index: true},
-        name: String,
-        localHost: String,
-        discovery: {
-            localAddress: String,
-            localPort: Number,
-            localPortRange: Number,
-            addressResolver: String,
-            socketTimeout: Number,
-            ackTimeout: Number,
-            maxAckTimeout: Number,
-            networkTimeout: Number,
-            joinTimeout: Number,
-            threadPriority: Number,
-            heartbeatFrequency: Number,
-            maxMissedHeartbeats: Number,
-            maxMissedClientHeartbeats: Number,
-            topHistorySize: Number,
-            listener: String,
-            dataExchange: String,
-            metricsProvider: String,
-            reconnectCount: Number,
-            statisticsPrintFrequency: Number,
-            ipFinderCleanFrequency: Number,
-            authenticator: String,
-            forceServerMode: Boolean,
-            clientReconnectDisabled: Boolean,
-            kind: {type: String, enum: ['Vm', 'Multicast', 'S3', 'Cloud', 'GoogleStorage', 'Jdbc', 'SharedFs', 'ZooKeeper']},
-            Vm: {
-                addresses: [String]
-            },
-            Multicast: {
-                multicastGroup: String,
-                multicastPort: Number,
-                responseWaitTime: Number,
-                addressRequestAttempts: Number,
-                localAddress: String,
-                addresses: [String]
-            },
-            S3: {
-                bucketName: String
-            },
-            Cloud: {
-                credential: String,
-                credentialPath: String,
-                identity: String,
-                provider: String,
-                regions: [String],
-                zones: [String]
-            },
-            GoogleStorage: {
-                projectName: String,
-                bucketName: String,
-                serviceAccountP12FilePath: String,
-                serviceAccountId: String,
-                addrReqAttempts: String
-            },
-            Jdbc: {
-                initSchema: Boolean
-            },
-            SharedFs: {
-                path: String
-            },
-            ZooKeeper: {
-                curator: String,
-                zkConnectionString: String,
-                retryPolicy: {
-                    kind: {type: String, enum: ['ExponentialBackoff', 'BoundedExponentialBackoff', 'UntilElapsed',
-                        'NTimes', 'OneTime', 'Forever', 'Custom']},
-                    ExponentialBackoff: {
-                        baseSleepTimeMs: Number,
-                        maxRetries: Number,
-                        maxSleepMs: Number
-                    },
-                    BoundedExponentialBackoff: {
-                        baseSleepTimeMs: Number,
-                        maxSleepTimeMs: Number,
-                        maxRetries: Number
-                    },
-                    UntilElapsed: {
-                        maxElapsedTimeMs: Number,
-                        sleepMsBetweenRetries: Number
-                    },
-                    NTimes: {
-                        n: Number,
-                        sleepMsBetweenRetries: Number
-                    },
-                    OneTime: {
-                        sleepMsBetweenRetry: Number
-                    },
-                    Forever: {
-                        retryIntervalMs: Number
-                    },
-                    Custom: {
-                        className: String
-                    }
-                },
-                basePath: String,
-                serviceName: String,
-                allowDuplicateRegistrations: Boolean
-            }
-        },
-        atomicConfiguration: {
-            backups: Number,
-            cacheMode: {type: String, enum: ['LOCAL', 'REPLICATED', 'PARTITIONED']},
-            atomicSequenceReserveSize: Number
-        },
-        binaryConfiguration: {
-            idMapper: String,
-            nameMapper: String,
-            serializer: String,
-            typeConfigurations: [{
-                typeName: String,
-                idMapper: String,
-                nameMapper: String,
-                serializer: String,
-                enum: Boolean
-            }],
-            compactFooter: Boolean
-        },
-        caches: [{type: ObjectId, ref: 'Cache'}],
-        clockSyncSamples: Number,
-        clockSyncFrequency: Number,
-        deploymentMode: {type: String, enum: ['PRIVATE', 'ISOLATED', 'SHARED', 'CONTINUOUS']},
-        discoveryStartupDelay: Number,
-        igfsThreadPoolSize: Number,
-        igfss: [{type: ObjectId, ref: 'Igfs'}],
-        includeEventTypes: [String],
-        managementThreadPoolSize: Number,
-        marshaller: {
-            kind: {type: String, enum: ['OptimizedMarshaller', 'JdkMarshaller']},
-            OptimizedMarshaller: {
-                poolSize: Number,
-                requireSerializable: Boolean
-            }
-        },
-        marshalLocalJobs: Boolean,
-        marshallerCacheKeepAliveTime: Number,
-        marshallerCacheThreadPoolSize: Number,
-        metricsExpireTime: Number,
-        metricsHistorySize: Number,
-        metricsLogFrequency: Number,
-        metricsUpdateFrequency: Number,
-        networkTimeout: Number,
-        networkSendRetryDelay: Number,
-        networkSendRetryCount: Number,
-        communication: {
-            listener: String,
-            localAddress: String,
-            localPort: Number,
-            localPortRange: Number,
-            sharedMemoryPort: Number,
-            directBuffer: Boolean,
-            directSendBuffer: Boolean,
-            idleConnectionTimeout: Number,
-            connectTimeout: Number,
-            maxConnectTimeout: Number,
-            reconnectCount: Number,
-            socketSendBuffer: Number,
-            socketReceiveBuffer: Number,
-            messageQueueLimit: Number,
-            slowClientQueueLimit: Number,
-            tcpNoDelay: Boolean,
-            ackSendThreshold: Number,
-            unacknowledgedMessagesBufferSize: Number,
-            socketWriteTimeout: Number,
-            selectorsCount: Number,
-            addressResolver: String
-        },
-        connector: {
-            enabled: Boolean,
-            jettyPath: String,
-            host: String,
-            port: Number,
-            portRange: Number,
-            idleTimeout: Number,
-            idleQueryCursorTimeout: Number,
-            idleQueryCursorCheckFrequency: Number,
-            receiveBufferSize: Number,
-            sendBufferSize: Number,
-            sendQueueLimit: Number,
-            directBuffer: Boolean,
-            noDelay: Boolean,
-            selectorCount: Number,
-            threadPoolSize: Number,
-            messageInterceptor: String,
-            secretKey: String,
-            sslEnabled: Boolean,
-            sslClientAuth: Boolean,
-            sslFactory: String
-        },
-        peerClassLoadingEnabled: Boolean,
-        peerClassLoadingLocalClassPathExclude: [String],
-        peerClassLoadingMissedResourcesCacheSize: Number,
-        peerClassLoadingThreadPoolSize: Number,
-        publicThreadPoolSize: Number,
-        swapSpaceSpi: {
-            kind: {type: String, enum: ['FileSwapSpaceSpi']},
-            FileSwapSpaceSpi: {
-                baseDirectory: String,
-                readStripesNumber: Number,
-                maximumSparsity: Number,
-                maxWriteQueueSize: Number,
-                writeBufferSize: Number
-            }
-        },
-        systemThreadPoolSize: Number,
-        timeServerPortBase: Number,
-        timeServerPortRange: Number,
-        transactionConfiguration: {
-            defaultTxConcurrency: {type: String, enum: ['OPTIMISTIC', 'PESSIMISTIC']},
-            defaultTxIsolation: {type: String, enum: ['READ_COMMITTED', 'REPEATABLE_READ', 'SERIALIZABLE']},
-            defaultTxTimeout: Number,
-            pessimisticTxLogLinger: Number,
-            pessimisticTxLogSize: Number,
-            txSerializableEnabled: Boolean,
-            txManagerFactory: String
-        },
-        sslEnabled: Boolean,
-        sslContextFactory: {
-            keyAlgorithm: String,
-            keyStoreFilePath: String,
-            keyStoreType: String,
-            protocol: String,
-            trustStoreFilePath: String,
-            trustStoreType: String,
-            trustManagers: [String]
-        },
-        rebalanceThreadPoolSize: Number,
-        attributes: [{name: String, value: String}],
-        collision: {
-            kind: {type: String, enum: ['Noop', 'PriorityQueue', 'FifoQueue', 'JobStealing', 'Custom']},
-            PriorityQueue: {
-                parallelJobsNumber: Number,
-                waitingJobsNumber: Number,
-                priorityAttributeKey: String,
-                jobPriorityAttributeKey: String,
-                defaultPriority: Number,
-                starvationIncrement: Number,
-                starvationPreventionEnabled: Boolean
-            },
-            FifoQueue: {
-                parallelJobsNumber: Number,
-                waitingJobsNumber: Number
-            },
-            JobStealing: {
-                activeJobsThreshold: Number,
-                waitJobsThreshold: Number,
-                messageExpireTime: Number,
-                maximumStealingAttempts: Number,
-                stealingEnabled: Boolean,
-                stealingAttributes: [{name: String, value: String}],
-                externalCollisionListener: String
-            },
-            Custom: {
-                class: String
-            }
-        },
-        failoverSpi: [{
-            kind: {type: String, enum: ['JobStealing', 'Never', 'Always', 'Custom']},
-            JobStealing: {
-                maximumFailoverAttempts: Number
-            },
-            Always: {
-                maximumFailoverAttempts: Number
-            },
-            Custom: {
-                class: String
-            }
-        }],
-        logger: {
-            kind: {type: 'String', enum: ['Log4j2', 'Null', 'Java', 'JCL', 'SLF4J', 'Log4j', 'Custom']},
-            Log4j2: {
-                level: {type: String, enum: ['OFF', 'FATAL', 'ERROR', 'WARN', 'INFO', 'DEBUG', 'TRACE', 'ALL']},
-                path: String
-            },
-            Log4j: {
-                mode: {type: String, enum: ['Default', 'Path']},
-                level: {type: String, enum: ['OFF', 'FATAL', 'ERROR', 'WARN', 'INFO', 'DEBUG', 'TRACE', 'ALL']},
-                path: String
-            },
-            Custom: {
-                class: String
-            }
-        }
-    });
-
-    // Install deep populate plugin.
-    ClusterSchema.plugin(deepPopulate, {
-        whitelist: [
-            'caches',
-            'caches.domains',
-            'igfss'
-        ]
-    });
-
-    // Define Cluster model.
-    result.Cluster = mongoose.model('Cluster', ClusterSchema);
-
-    result.ClusterDefaultPopulate = '';
-
-    // Define Notebook schema.
-    const NotebookSchema = new Schema({
-        space: {type: ObjectId, ref: 'Space', index: true},
-        name: String,
-        expandedParagraphs: [Number],
-        paragraphs: [{
-            name: String,
-            query: String,
-            editor: Boolean,
-            result: {type: String, enum: ['none', 'table', 'bar', 'pie', 'line', 'area']},
-            pageSize: Number,
-            timeLineSpan: String,
-            hideSystemColumns: Boolean,
-            cacheName: String,
-            chartsOptions: {barChart: {stacked: Boolean}, areaChart: {style: String}},
-            rate: {
-                value: Number,
-                unit: Number
-            }
-        }]
-    });
-
-    // Define Notebook model.
-    result.Notebook = mongoose.model('Notebook', NotebookSchema);
-
-    result.handleError = function(res, err) {
-        // TODO IGNITE-843 Send error to admin
-        res.status(err.code || 500).send(err.message);
-    };
-
-    /**
-     * Query for user spaces.
-     *
-     * @param userId User ID.
-     * @param {Boolean} demo Is need use demo space.
-     * @returns {Promise}
-     */
-    result.spaces = function(userId, demo) {
-        return result.Space.find({owner: userId, demo: !!demo}).lean().exec();
-    };
-
-    /**
-     * Extract IDs from user spaces.
-     *
-     * @param userId User ID.
-     * @param {Boolean} demo Is need use demo space.
-     * @returns {Promise}
-     */
-    result.spaceIds = function(userId, demo) {
-        return result.spaces(userId, demo)
-            .then((spaces) => spaces.map((space) => space._id));
-    };
-
-    // Registering the routes of all plugin modules
-    for (const name in pluginMongo) {
-        if (pluginMongo.hasOwnProperty(name))
-            pluginMongo[name].register(mongoose, deepPopulate, result);
-    }
-
-    return result;
-};

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/src/main/js/serve/routes/admin.js
----------------------------------------------------------------------
diff --git a/modules/web-console/src/main/js/serve/routes/admin.js b/modules/web-console/src/main/js/serve/routes/admin.js
deleted file mode 100644
index 3c2e728..0000000
--- a/modules/web-console/src/main/js/serve/routes/admin.js
+++ /dev/null
@@ -1,126 +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.
- */
-
-'use strict';
-
-// Fire me up!
-
-module.exports = {
-    implements: 'admin-routes',
-    inject: ['require(lodash)', 'require(express)', 'settings', 'mail', 'mongo']
-};
-
-module.exports.factory = function(_, express, settings, mail, mongo) {
-    return new Promise((factoryResolve) => {
-        const router = new express.Router();
-
-        /**
-         * Get list of user accounts.
-         */
-        router.post('/list', (req, res) => {
-
-            Promise.all([
-                mongo.Space.aggregate([
-                    {$match: {demo: false}},
-                    {$lookup: {from: 'clusters', localField: '_id', foreignField: 'space', as: 'clusters'}},
-                    {$lookup: {from: 'caches', localField: '_id', foreignField: 'space', as: 'caches'}},
-                    {$lookup: {from: 'domainmodels', localField: '_id', foreignField: 'space', as: 'domainmodels'}},
-                    {$lookup: {from: 'igfs', localField: '_id', foreignField: 'space', as: 'igfs'}},
-                    {$project: {
-                        owner: 1,
-                        clusters: {$size: '$clusters'},
-                        models: {$size: '$domainmodels'},
-                        caches: {$size: '$caches'},
-                        igfs: {$size: '$igfs'}
-                    }}
-                ]).exec(),
-                mongo.Account.find({}).sort('firstName lastName').lean().exec()
-            ])
-            .then((values) => {
-                const counters = _.keyBy(values[0], 'owner');
-                const accounts = values[1];
-
-                return accounts.map((account) => {
-                    account.counters = _.omit(counters[account._id], '_id', 'owner');
-
-                    return account;
-                });
-            })
-            .then((users) => res.json(users))
-            .catch((err) => mongo.handleError(res, err));
-        });
-
-        // Remove user.
-        router.post('/remove', (req, res) => {
-            const userId = req.body.userId;
-
-            mongo.Account.findByIdAndRemove(userId).exec()
-                .then((user) => {
-                    res.sendStatus(200);
-
-                    return mongo.spaceIds(userId)
-                        .then((spaceIds) => Promise.all([
-                            mongo.Cluster.remove({space: {$in: spaceIds}}).exec(),
-                            mongo.Cache.remove({space: {$in: spaceIds}}).exec(),
-                            mongo.DomainModel.remove({space: {$in: spaceIds}}).exec(),
-                            mongo.Igfs.remove({space: {$in: spaceIds}}).exec(),
-                            mongo.Notebook.remove({space: {$in: spaceIds}}).exec(),
-                            mongo.Space.remove({owner: userId}).exec()
-                        ]))
-                        .then(() => user)
-                        .catch((err) => console.error(`Failed to cleanup spaces [user=${user.username}, err=${err}`));
-                })
-                .then((user) =>
-                    mail.send(user, 'Your account was deleted',
-                        `Hello ${user.firstName} ${user.lastName}!<br><br>` +
-                        `You are receiving this email because your account for <a href="http://${req.headers.host}">${settings.smtp.username}</a> was removed.`,
-                        'Account was removed, but failed to send email notification to user!')
-                )
-                .catch((err) => mongo.handleError(res, err));
-        });
-
-        // Save user.
-        router.post('/save', (req, res) => {
-            const params = req.body;
-
-            mongo.Account.findByIdAndUpdate(params.userId, {admin: params.adminFlag}).exec()
-                .then(() => res.sendStatus(200))
-                .catch((err) => mongo.handleError(res, err));
-        });
-
-        // Become user.
-        router.get('/become', (req, res) => {
-            mongo.Account.findById(req.query.viewedUserId).exec()
-                .then((viewedUser) => {
-                    req.session.viewedUser = viewedUser;
-
-                    res.sendStatus(200);
-                })
-                .catch(() => res.sendStatus(404));
-        });
-
-        // Revert to your identity.
-        router.get('/revert/identity', (req, res) => {
-            req.session.viewedUser = null;
-
-            return res.sendStatus(200);
-        });
-
-        factoryResolve(router);
-    });
-};
-

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/src/main/js/serve/routes/agent.js
----------------------------------------------------------------------
diff --git a/modules/web-console/src/main/js/serve/routes/agent.js b/modules/web-console/src/main/js/serve/routes/agent.js
deleted file mode 100644
index 48ec131..0000000
--- a/modules/web-console/src/main/js/serve/routes/agent.js
+++ /dev/null
@@ -1,81 +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.
- */
-
-'use strict';
-
-// Fire me up!
-
-module.exports = {
-    implements: 'agent-routes',
-    inject: ['require(lodash)', 'require(express)', 'require(fs)', 'require(jszip)', 'settings', 'agent-manager']
-};
-
-/**
- * @param _
- * @param express
- * @param fs
- * @param JSZip
- * @param settings
- * @param {AgentManager} agentMgr
- * @returns {Promise}
- */
-module.exports.factory = function(_, express, fs, JSZip, settings, agentMgr) {
-    return new Promise((resolveFactory) => {
-        const router = new express.Router();
-
-        /* Get grid topology. */
-        router.get('/download/zip', (req, res) => {
-            const latest = agentMgr.supportedAgents.latest;
-
-            if (_.isEmpty(latest))
-                return res.status(500).send('Missing agent zip on server. Please ask webmaster to upload agent zip!');
-
-            const agentFld = latest.fileName.substr(0, latest.fileName.length - 4);
-            const agentZip = latest.fileName;
-            const agentPathZip = latest.filePath;
-
-            // Read a zip file.
-            fs.readFile(agentPathZip, (errFs, data) => {
-                if (errFs)
-                    return res.download(agentPathZip, agentZip);
-
-                // Set the archive name.
-                res.attachment(agentZip);
-
-                JSZip.loadAsync(data)
-                    .then((zip) => {
-                        const prop = [];
-
-                        const host = req.hostname.match(/:/g) ? req.hostname.slice(0, req.hostname.indexOf(':')) : req.hostname;
-
-                        prop.push('tokens=' + req.user.token);
-                        prop.push('server-uri=' + (settings.agent.SSLOptions ? 'https' : 'http') + '://' + host + ':' + settings.agent.port);
-                        prop.push('#Uncomment following options if needed:');
-                        prop.push('#node-uri=http://localhost:8080');
-                        prop.push('#driver-folder=./jdbc-drivers');
-
-                        zip.file(agentFld + '/default.properties', prop.join('\n'));
-
-                        zip.generateAsync({type: 'nodebuffer', platform: 'UNIX'})
-                            .then((buffer) => res.send(buffer));
-                    });
-            });
-        });
-
-        resolveFactory(router);
-    });
-};

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/src/main/js/serve/routes/caches.js
----------------------------------------------------------------------
diff --git a/modules/web-console/src/main/js/serve/routes/caches.js b/modules/web-console/src/main/js/serve/routes/caches.js
deleted file mode 100644
index ed1f257..0000000
--- a/modules/web-console/src/main/js/serve/routes/caches.js
+++ /dev/null
@@ -1,132 +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.
- */
-
-'use strict';
-
-// Fire me up!
-
-module.exports = {
-    implements: 'caches-routes',
-    inject: ['require(lodash)', 'require(express)', 'mongo']
-};
-
-module.exports.factory = function(_, express, mongo) {
-    return new Promise((factoryResolve) => {
-        const router = new express.Router();
-
-        /**
-         * Get spaces and caches accessed for user account.
-         *
-         * @param req Request.
-         * @param res Response.
-         */
-        router.post('/list', (req, res) => {
-            const result = {};
-            let spaceIds = [];
-
-            // Get owned space and all accessed space.
-            mongo.spaces(req.currentUserId(), req.header('IgniteDemoMode'))
-                .then((spaces) => {
-                    result.spaces = spaces;
-                    spaceIds = spaces.map((space) => space._id);
-
-                    return mongo.Cluster.find({space: {$in: spaceIds}}).sort('name').lean().exec();
-                })
-                .then((clusters) => {
-                    result.clusters = clusters;
-
-                    return mongo.DomainModel.find({space: {$in: spaceIds}}).sort('name').lean().exec();
-                })
-                .then((domains) => {
-                    result.domains = domains;
-
-                    return mongo.Cache.find({space: {$in: spaceIds}}).sort('name').lean().exec();
-                })
-                .then((caches) => {
-                    result.caches = caches;
-
-                    res.json(result);
-                })
-                .catch((err) => mongo.handleError(res, err));
-        });
-
-        /**
-         * Save cache.
-         */
-        router.post('/save', (req, res) => {
-            const params = req.body;
-            const clusters = params.clusters;
-            const domains = params.domains;
-
-            mongo.Cache.findOne({space: params.space, name: params.name}).exec()
-                .then((existingCache) => {
-                    const cacheId = params._id;
-
-                    if (existingCache && cacheId !== existingCache._id.toString())
-                        return res.status(500).send('Cache with name: "' + existingCache.name + '" already exist.');
-
-                    if (cacheId) {
-                        return mongo.Cache.update({_id: cacheId}, params, {upsert: true}).exec()
-                            .then(() => mongo.Cluster.update({_id: {$in: clusters}}, {$addToSet: {caches: cacheId}}, {multi: true}).exec())
-                            .then(() => mongo.Cluster.update({_id: {$nin: clusters}}, {$pull: {caches: cacheId}}, {multi: true}).exec())
-                            .then(() => mongo.DomainModel.update({_id: {$in: domains}}, {$addToSet: {caches: cacheId}}, {multi: true}).exec())
-                            .then(() => mongo.DomainModel.update({_id: {$nin: domains}}, {$pull: {caches: cacheId}}, {multi: true}).exec())
-                            .then(() => res.send(cacheId));
-                    }
-
-                    return (new mongo.Cache(params)).save()
-                        .then((cache) =>
-                            mongo.Cluster.update({_id: {$in: clusters}}, {$addToSet: {caches: cache._id}}, {multi: true}).exec()
-                                .then(() => mongo.DomainModel.update({_id: {$in: domains}}, {$addToSet: {caches: cache._id}}, {multi: true}).exec())
-                                .then(() => res.send(cache._id))
-                        );
-                })
-                .catch((err) => mongo.handleError(res, err));
-        });
-
-        /**
-         * Remove cache by ._id.
-         */
-        router.post('/remove', (req, res) => {
-            const params = req.body;
-            const cacheId = params._id;
-
-            mongo.Cluster.update({caches: {$in: [cacheId]}}, {$pull: {caches: cacheId}}, {multi: true}).exec()
-                .then(() => mongo.DomainModel.update({caches: {$in: [cacheId]}}, {$pull: {caches: cacheId}}, {multi: true}).exec())
-                .then(() => mongo.Cache.remove(params).exec())
-                .then(() => res.sendStatus(200))
-                .catch((err) => mongo.handleError(res, err));
-        });
-
-        /**
-         * Remove all caches.
-         */
-        router.post('/remove/all', (req, res) => {
-            mongo.spaceIds(req.currentUserId(), req.header('IgniteDemoMode'))
-                .then((spaceIds) =>
-                    mongo.Cluster.update({space: {$in: spaceIds}}, {caches: []}, {multi: true}).exec()
-                        .then(() => mongo.DomainModel.update({space: {$in: spaceIds}}, {caches: []}, {multi: true}).exec())
-                        .then(() => mongo.Cache.remove({space: {$in: spaceIds}}).exec())
-                )
-                .then(() => res.sendStatus(200))
-                .catch((err) => mongo.handleError(res, err));
-        });
-
-        factoryResolve(router);
-    });
-};
-

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/src/main/js/serve/routes/clusters.js
----------------------------------------------------------------------
diff --git a/modules/web-console/src/main/js/serve/routes/clusters.js b/modules/web-console/src/main/js/serve/routes/clusters.js
deleted file mode 100644
index 9d13990..0000000
--- a/modules/web-console/src/main/js/serve/routes/clusters.js
+++ /dev/null
@@ -1,146 +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.
- */
-
-'use strict';
-
-// Fire me up!
-
-module.exports = {
-    implements: 'clusters-routes',
-    inject: ['require(lodash)', 'require(express)', 'mongo']
-};
-
-module.exports.factory = function(_, express, mongo) {
-    return new Promise((factoryResolve) => {
-        const router = new express.Router();
-
-        /**
-         * Get spaces and clusters accessed for user account.
-         *
-         * @param req Request.
-         * @param res Response.
-         */
-        router.post('/list', (req, res) => {
-            const result = {};
-            let spaceIds = [];
-            let domains = {};
-
-            mongo.spaces(req.currentUserId(), req.header('IgniteDemoMode'))
-                .then((spaces) => {
-                    result.spaces = spaces;
-                    spaceIds = spaces.map((space) => space._id);
-
-                    return mongo.DomainModel.find({space: {$in: spaceIds}}).lean().exec();
-                })
-                .then((_domains) => {
-                    domains = _domains.reduce((map, obj) => {
-                        map[obj._id] = obj;
-
-                        return map;
-                    }, {});
-
-                    return mongo.Cache.find({space: {$in: spaceIds}}).sort('name').lean().exec();
-                })
-                .then((caches) => {
-                    _.forEach(caches, (cache) => {
-                        cache.domains = _.map(cache.domains, (domainId) => domains[domainId]);
-                    });
-
-                    result.caches = caches;
-
-                    return mongo.Igfs.find({space: {$in: spaceIds}}).sort('name').lean().exec();
-                })
-                .then((igfss) => {
-                    result.igfss = igfss;
-
-                    return mongo.Cluster.find({space: {$in: spaceIds}}).sort('name').deepPopulate(mongo.ClusterDefaultPopulate).lean().exec();
-                })
-                .then((clusters) => {
-                    result.clusters = clusters;
-
-                    res.json(result);
-                })
-                .catch((err) => mongo.handleError(res, err));
-        });
-
-        /**
-         * Save cluster.
-         */
-        router.post('/save', (req, res) => {
-            const params = req.body;
-            const caches = params.caches;
-            const igfss = params.igfss;
-
-            mongo.Cluster.findOne({space: params.space, name: params.name}).exec()
-                .then((existingCluster) => {
-                    const clusterId = params._id;
-
-                    if (existingCluster && clusterId !== existingCluster._id.toString())
-                        throw new Error('Cluster with name: "' + existingCluster.name + '" already exist.');
-
-                    if (clusterId) {
-                        return mongo.Cluster.update({_id: clusterId}, params, {upsert: true}).exec()
-                            .then(() => mongo.Cache.update({_id: {$in: caches}}, {$addToSet: {clusters: clusterId}}, {multi: true}).exec())
-                            .then(() => mongo.Cache.update({_id: {$nin: caches}}, {$pull: {clusters: clusterId}}, {multi: true}).exec())
-                            .then(() => mongo.Igfs.update({_id: {$in: igfss}}, {$addToSet: {clusters: clusterId}}, {multi: true}).exec())
-                            .then(() => mongo.Igfs.update({_id: {$nin: igfss}}, {$pull: {clusters: clusterId}}, {multi: true}).exec())
-                            .then(() => res.send(clusterId));
-                    }
-
-                    return (new mongo.Cluster(params)).save()
-                        .then((cluster) =>
-                            mongo.Cache.update({_id: {$in: caches}}, {$addToSet: {clusters: cluster._id}}, {multi: true}).exec()
-                                .then(() => mongo.Cache.update({_id: {$nin: caches}}, {$pull: {clusters: cluster._id}}, {multi: true}).exec())
-                                .then(() => mongo.Igfs.update({_id: {$in: igfss}}, {$addToSet: {clusters: cluster._id}}, {multi: true}).exec())
-                                .then(() => mongo.Igfs.update({_id: {$nin: igfss}}, {$pull: {clusters: cluster._id}}, {multi: true}).exec())
-                                .then(() => res.send(cluster._id))
-                        );
-                })
-                .catch((err) => mongo.handleError(res, err));
-        });
-
-        /**
-         * Remove cluster by ._id.
-         */
-        router.post('/remove', (req, res) => {
-            const params = req.body;
-            const clusterId = params._id;
-
-            mongo.Cache.update({clusters: {$in: [clusterId]}}, {$pull: {clusters: clusterId}}, {multi: true}).exec()
-                .then(() => mongo.Igfs.update({clusters: {$in: [clusterId]}}, {$pull: {clusters: clusterId}}, {multi: true}).exec())
-                .then(() => mongo.Cluster.remove(params).exec())
-                .then(() => res.sendStatus(200))
-                .catch((err) => mongo.handleError(res, err));
-        });
-
-        /**
-         * Remove all clusters.
-         */
-        router.post('/remove/all', (req, res) => {
-            // Get owned space and all accessed space.
-            mongo.spaceIds(req.currentUserId(), req.header('IgniteDemoMode'))
-                .then((spaceIds) => mongo.Cache.update({space: {$in: spaceIds}}, {clusters: []}, {multi: true}).exec()
-                    .then(() => mongo.Igfs.update({space: {$in: spaceIds}}, {clusters: []}, {multi: true}).exec())
-                    .then(() => mongo.Cluster.remove({space: {$in: spaceIds}}).exec())
-                )
-                .then(() => res.sendStatus(200))
-                .catch((err) => mongo.handleError(res, err));
-        });
-
-        factoryResolve(router);
-    });
-};

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/src/main/js/serve/routes/demo.js
----------------------------------------------------------------------
diff --git a/modules/web-console/src/main/js/serve/routes/demo.js b/modules/web-console/src/main/js/serve/routes/demo.js
deleted file mode 100644
index dd47eb9..0000000
--- a/modules/web-console/src/main/js/serve/routes/demo.js
+++ /dev/null
@@ -1,135 +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.
- */
-
-'use strict';
-
-// Fire me up!
-
-module.exports = {
-    implements: 'demo-routes',
-    inject: [
-        'require(lodash)',
-        'require(express)',
-        'settings',
-        'mongo',
-        'require(./demo/domains.json)',
-        'require(./demo/caches.json)',
-        'require(./demo/igfss.json)',
-        'require(./demo/clusters.json)'
-    ]
-};
-
-module.exports.factory = (_, express, settings, mongo, domains, caches, igfss, clusters) => {
-    return new Promise((factoryResolve) => {
-        const router = new express.Router();
-
-        /**
-         * Reset demo configuration.
-         */
-        router.post('/reset', (req, res) => {
-            mongo.spaces(req.user._id, true)
-                .then((spaces) => {
-                    if (spaces.length) {
-                        const spaceIds = spaces.map((space) => space._id);
-
-                        return Promise.all([
-                            mongo.Cluster.remove({space: {$in: spaceIds}}).exec(),
-                            mongo.Cache.remove({space: {$in: spaceIds}}).exec(),
-                            mongo.DomainModel.remove({space: {$in: spaceIds}}).exec(),
-                            mongo.Igfs.remove({space: {$in: spaceIds}}).exec()
-                        ]).then(() => spaces[0]);
-                    }
-
-                    return new mongo.Space({name: 'Demo space', owner: req.user._id, demo: true}).save();
-                })
-                .then((space) => {
-                    return Promise.all(_.map(clusters, (cluster) => {
-                        const clusterDoc = new mongo.Cluster(cluster);
-
-                        clusterDoc.space = space._id;
-
-                        return clusterDoc.save();
-                    }));
-                })
-                .then((clusterDocs) => {
-                    return _.map(clusterDocs, (cluster) => {
-                        const addCacheToCluster = (cacheDoc) => cluster.caches.push(cacheDoc._id);
-                        const addIgfsToCluster = (igfsDoc) => cluster.igfss.push(igfsDoc._id);
-
-                        if (cluster.name.endsWith('-caches')) {
-                            const cachePromises = _.map(caches, (cacheData) => {
-                                const cache = new mongo.Cache(cacheData);
-
-                                cache.space = cluster.space;
-                                cache.clusters.push(cluster._id);
-
-                                return cache.save()
-                                    .then((cacheDoc) => {
-                                        const domainData = _.find(domains, (item) =>
-                                            item.databaseTable === cacheDoc.name.slice(0, -5).toUpperCase());
-
-                                        if (domainData) {
-                                            const domain = new mongo.DomainModel(domainData);
-
-                                            domain.space = cacheDoc.space;
-                                            domain.caches.push(cacheDoc._id);
-
-                                            return domain.save()
-                                                .then((domainDoc) => {
-                                                    cacheDoc.domains.push(domainDoc._id);
-
-                                                    return cacheDoc.save();
-                                                });
-                                        }
-
-                                        return cacheDoc;
-                                    });
-                            });
-
-                            return Promise.all(cachePromises)
-                                .then((cacheDocs) => {
-                                    _.forEach(cacheDocs, addCacheToCluster);
-
-                                    return cluster.save();
-                                });
-                        }
-
-                        if (cluster.name.endsWith('-igfs')) {
-                            return Promise.all(_.map(igfss, (igfs) => {
-                                const igfsDoc = new mongo.Igfs(igfs);
-
-                                igfsDoc.space = cluster.space;
-                                igfsDoc.clusters.push(cluster._id);
-
-                                return igfsDoc.save();
-                            }))
-                            .then((igfsDocs) => {
-                                _.forEach(igfsDocs, addIgfsToCluster);
-
-                                return cluster.save();
-                            });
-                        }
-                    });
-                })
-                .then(() => res.sendStatus(200))
-                .catch((err) => res.status(500).send(err.message));
-        });
-
-        factoryResolve(router);
-    });
-};
-

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/src/main/js/serve/routes/demo/caches.json
----------------------------------------------------------------------
diff --git a/modules/web-console/src/main/js/serve/routes/demo/caches.json b/modules/web-console/src/main/js/serve/routes/demo/caches.json
deleted file mode 100644
index f7a8690..0000000
--- a/modules/web-console/src/main/js/serve/routes/demo/caches.json
+++ /dev/null
@@ -1,87 +0,0 @@
-[
-  {
-    "name": "CarCache",
-    "cacheMode": "PARTITIONED",
-    "atomicityMode": "ATOMIC",
-    "readThrough": true,
-    "writeThrough": true,
-    "sqlFunctionClasses": [],
-    "cacheStoreFactory": {
-      "kind": "CacheJdbcPojoStoreFactory",
-      "CacheJdbcPojoStoreFactory": {
-        "dataSourceBean": "dsH2",
-        "dialect": "H2"
-      }
-    },
-    "domains": [],
-    "clusters": []
-  },
-  {
-    "name": "ParkingCache",
-    "cacheMode": "PARTITIONED",
-    "atomicityMode": "ATOMIC",
-    "readThrough": true,
-    "writeThrough": true,
-    "sqlFunctionClasses": [],
-    "cacheStoreFactory": {
-      "kind": "CacheJdbcPojoStoreFactory",
-      "CacheJdbcPojoStoreFactory": {
-        "dataSourceBean": "dsH2",
-        "dialect": "H2"
-      }
-    },
-    "domains": [],
-    "clusters": []
-  },
-  {
-    "name": "CountryCache",
-    "cacheMode": "PARTITIONED",
-    "atomicityMode": "ATOMIC",
-    "readThrough": true,
-    "writeThrough": true,
-    "sqlFunctionClasses": [],
-    "cacheStoreFactory": {
-      "kind": "CacheJdbcPojoStoreFactory",
-      "CacheJdbcPojoStoreFactory": {
-        "dataSourceBean": "dsH2",
-        "dialect": "H2"
-      }
-    },
-    "domains": [],
-    "clusters": []
-  },
-  {
-    "name": "DepartmentCache",
-    "cacheMode": "PARTITIONED",
-    "atomicityMode": "ATOMIC",
-    "readThrough": true,
-    "writeThrough": true,
-    "sqlFunctionClasses": [],
-    "cacheStoreFactory": {
-      "kind": "CacheJdbcPojoStoreFactory",
-      "CacheJdbcPojoStoreFactory": {
-        "dataSourceBean": "dsH2",
-        "dialect": "H2"
-      }
-    },
-    "domains": [],
-    "clusters": []
-  },
-  {
-    "name": "EmployeeCache",
-    "cacheMode": "PARTITIONED",
-    "atomicityMode": "ATOMIC",
-    "readThrough": true,
-    "writeThrough": true,
-    "sqlFunctionClasses": [],
-    "cacheStoreFactory": {
-      "kind": "CacheJdbcPojoStoreFactory",
-      "CacheJdbcPojoStoreFactory": {
-        "dataSourceBean": "dsH2",
-        "dialect": "H2"
-      }
-    },
-    "domains": [],
-    "clusters": []
-  }
-]

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/src/main/js/serve/routes/demo/clusters.json
----------------------------------------------------------------------
diff --git a/modules/web-console/src/main/js/serve/routes/demo/clusters.json b/modules/web-console/src/main/js/serve/routes/demo/clusters.json
deleted file mode 100644
index 014b519..0000000
--- a/modules/web-console/src/main/js/serve/routes/demo/clusters.json
+++ /dev/null
@@ -1,50 +0,0 @@
-[
-  {
-    "name": "cluster-igfs",
-    "connector": {
-      "noDelay": true
-    },
-    "communication": {
-      "tcpNoDelay": true
-    },
-    "igfss": [],
-    "caches": [],
-    "binaryConfiguration": {
-      "compactFooter": true,
-      "typeConfigurations": []
-    },
-    "discovery": {
-      "kind": "Multicast",
-      "Multicast": {
-        "addresses": ["127.0.0.1:47500..47510"]
-      },
-      "Vm": {
-        "addresses": ["127.0.0.1:47500..47510"]
-      }
-    }
-  },
-  {
-    "name": "cluster-caches",
-    "connector": {
-      "noDelay": true
-    },
-    "communication": {
-      "tcpNoDelay": true
-    },
-    "igfss": [],
-    "caches": [],
-    "binaryConfiguration": {
-      "compactFooter": true,
-      "typeConfigurations": []
-    },
-    "discovery": {
-      "kind": "Multicast",
-      "Multicast": {
-        "addresses": ["127.0.0.1:47500..47510"]
-      },
-      "Vm": {
-        "addresses": ["127.0.0.1:47500..47510"]
-      }
-    }
-  }
-]


[29/52] ignite git commit: Web Console beta-3.

Posted by ak...@apache.org.
http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/frontend/controllers/domains-controller.js
----------------------------------------------------------------------
diff --git a/modules/web-console/frontend/controllers/domains-controller.js b/modules/web-console/frontend/controllers/domains-controller.js
new file mode 100644
index 0000000..e520494
--- /dev/null
+++ b/modules/web-console/frontend/controllers/domains-controller.js
@@ -0,0 +1,1790 @@
+/*
+ * 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.
+ */
+
+// Controller for Domain model screen.
+export default ['domainsController', [
+    '$rootScope', '$scope', '$http', '$state', '$filter', '$timeout', '$modal', 'IgniteLegacyUtils', 'IgniteMessages', 'IgniteFocus', 'IgniteConfirm', 'IgniteConfirmBatch', 'IgniteClone', 'IgniteLoading', 'IgniteModelNormalizer', 'IgniteUnsavedChangesGuard', 'IgniteAgentMonitor', 'IgniteLegacyTable', 'igniteConfigurationResource', 'IgniteErrorPopover', 'IgniteFormUtils',
+    function($root, $scope, $http, $state, $filter, $timeout, $modal, LegacyUtils, Messages, Focus, Confirm, ConfirmBatch, Clone, Loading, ModelNormalizer, UnsavedChangesGuard, IgniteAgentMonitor, LegacyTable, Resource, ErrorPopover, FormUtils) {
+        UnsavedChangesGuard.install($scope);
+
+        const emptyDomain = {empty: true};
+
+        let __original_value;
+
+        const blank = {};
+
+        // We need to initialize backupItem with empty object in order to properly used from angular directives.
+        $scope.backupItem = emptyDomain;
+
+        $scope.ui = FormUtils.formUI();
+        $scope.ui.activePanels = [0, 1];
+        $scope.ui.topPanels = [0, 1, 2];
+
+        const IMPORT_DM_NEW_CACHE = 1;
+        const IMPORT_DM_ASSOCIATE_CACHE = 2;
+
+        /**
+         * Convert some name to valid java package name.
+         *
+         * @param name to convert.
+         * @returns {string} Valid java package name.
+         */
+        const _toJavaPackage = (name) => {
+            return name ? name.replace(/[^A-Za-z_0-9/.]+/g, '_') : 'org';
+        };
+
+        const _packageNameUpdate = (event, user) => {
+            if (_.isNil(user))
+                return;
+
+            $scope.ui.packageNameUserInput = _toJavaPackage(user.email.replace('@', '.').split('.').reverse().join('.') + '.model');
+        };
+
+        _packageNameUpdate(null, $root.user);
+
+        $scope.$on('$destroy', $root.$on('user', _packageNameUpdate));
+
+        $scope.ui.builtinKeys = true;
+        $scope.ui.usePrimitives = true;
+        $scope.ui.generateAliases = true;
+        $scope.ui.generatedCachesClusters = [];
+
+        function _mapCaches(caches) {
+            return _.map(caches, (cache) => {
+                return {label: cache.name, value: cache._id, cache};
+            });
+        }
+
+        $scope.contentVisible = function() {
+            const item = $scope.backupItem;
+
+            return !item.empty && (!item._id || _.find($scope.displayedRows, {_id: item._id}));
+        };
+
+        $scope.getModel = LegacyUtils.getModel;
+        $scope.javaBuiltInClasses = LegacyUtils.javaBuiltInClasses;
+        $scope.compactJavaName = FormUtils.compactJavaName;
+        $scope.widthIsSufficient = FormUtils.widthIsSufficient;
+        $scope.saveBtnTipText = FormUtils.saveBtnTipText;
+
+        $scope.tableSave = function(field, index, stopEdit) {
+            if (LegacyTable.tableEditing({model: 'table-index-fields'}, LegacyTable.tableEditedRowIndex())) {
+                if ($scope.tableIndexItemSaveVisible(field, index))
+                    return $scope.tableIndexItemSave(field, field.indexIdx, index, stopEdit);
+            }
+            else {
+                switch (field.type) {
+                    case 'fields':
+                    case 'aliases':
+                        if (LegacyTable.tablePairSaveVisible(field, index))
+                            return LegacyTable.tablePairSave($scope.tablePairValid, $scope.backupItem, field, index, stopEdit);
+
+                        break;
+
+                    case 'indexes':
+                        if ($scope.tableIndexSaveVisible(field, index))
+                            return $scope.tableIndexSave(field, index, stopEdit);
+
+                        break;
+
+                    case 'table-db-fields':
+                        if ($scope.tableDbFieldSaveVisible(field, index))
+                            return $scope.tableDbFieldSave(field, index, stopEdit);
+
+                        break;
+
+                    default:
+                }
+            }
+
+            return true;
+        };
+
+        $scope.tableReset = (trySave) => {
+            const field = LegacyTable.tableField();
+
+            if (trySave && LegacyUtils.isDefined(field) && !$scope.tableSave(field, LegacyTable.tableEditedRowIndex(), true))
+                return false;
+
+            LegacyTable.tableReset();
+
+            return true;
+        };
+
+        $scope.tableNewItem = function(field) {
+            if ($scope.tableReset(true))
+                LegacyTable.tableNewItem(field);
+        };
+
+        $scope.tableNewItemActive = LegacyTable.tableNewItemActive;
+
+        $scope.tableStartEdit = function(item, field, index) {
+            if ($scope.tableReset(true))
+                LegacyTable.tableStartEdit(item, field, index, $scope.tableSave);
+        };
+
+        $scope.tableEditing = LegacyTable.tableEditing;
+
+        $scope.tableRemove = function(item, field, index) {
+            if ($scope.tableReset(true))
+                LegacyTable.tableRemove(item, field, index);
+        };
+
+        $scope.tablePairSave = LegacyTable.tablePairSave;
+        $scope.tablePairSaveVisible = LegacyTable.tablePairSaveVisible;
+
+        $scope.queryFieldsTbl = {
+            type: 'fields',
+            model: 'fields',
+            focusId: 'QryField',
+            ui: 'table-pair',
+            keyName: 'name',
+            valueName: 'className',
+            save: $scope.tableSave
+        };
+
+        $scope.aliasesTbl = {
+            type: 'aliases',
+            model: 'aliases',
+            focusId: 'Alias',
+            ui: 'table-pair',
+            keyName: 'field',
+            valueName: 'alias',
+            save: $scope.tableSave
+        };
+
+        $scope.queryMetadataVariants = LegacyUtils.mkOptions(['Annotations', 'Configuration']);
+
+        const INFO_CONNECT_TO_DB = 'Configure connection to database';
+        const INFO_SELECT_SCHEMAS = 'Select schemas to load tables from';
+        const INFO_SELECT_TABLES = 'Select tables to import as domain model';
+        const INFO_SELECT_OPTIONS = 'Select import domain model options';
+        const LOADING_JDBC_DRIVERS = {text: 'Loading JDBC drivers...'};
+        const LOADING_SCHEMAS = {text: 'Loading schemas...'};
+        const LOADING_TABLES = {text: 'Loading tables...'};
+        const SAVING_DOMAINS = {text: 'Saving domain model...'};
+
+        $scope.ui.invalidKeyFieldsTooltip = 'Found key types without configured key fields<br/>' +
+            'It may be a result of import tables from database without primary keys<br/>' +
+            'Key field for such key types should be configured manually';
+
+        $scope.indexType = LegacyUtils.mkOptions(['SORTED', 'FULLTEXT', 'GEOSPATIAL']);
+
+        const _dbPresets = [
+            {
+                db: 'Oracle',
+                jdbcDriverClass: 'oracle.jdbc.OracleDriver',
+                jdbcUrl: 'jdbc:oracle:thin:@[host]:[port]:[database]',
+                user: 'system'
+            },
+            {
+                db: 'DB2',
+                jdbcDriverClass: 'com.ibm.db2.jcc.DB2Driver',
+                jdbcUrl: 'jdbc:db2://[host]:[port]/[database]',
+                user: 'db2admin'
+            },
+            {
+                db: 'SQLServer',
+                jdbcDriverClass: 'com.microsoft.sqlserver.jdbc.SQLServerDriver',
+                jdbcUrl: 'jdbc:sqlserver://[host]:[port][;databaseName=database]'
+            },
+            {
+                db: 'PostgreSQL',
+                jdbcDriverClass: 'org.postgresql.Driver',
+                jdbcUrl: 'jdbc:postgresql://[host]:[port]/[database]',
+                user: 'sa'
+            },
+            {
+                db: 'MySQL',
+                jdbcDriverClass: 'com.mysql.jdbc.Driver',
+                jdbcUrl: 'jdbc:mysql://[host]:[port]/[database]',
+                user: 'root'
+            },
+            {
+                db: 'H2',
+                jdbcDriverClass: 'org.h2.Driver',
+                jdbcUrl: 'jdbc:h2:tcp://[host]/[database]',
+                user: 'sa'
+            }
+        ];
+
+        $scope.selectedPreset = {
+            db: 'General',
+            jdbcDriverJar: '',
+            jdbcDriverClass: '',
+            jdbcUrl: 'jdbc:[database]',
+            user: 'sa',
+            password: '',
+            tablesOnly: true
+        };
+
+        $scope.demoConnection = {
+            db: 'H2',
+            jdbcDriverClass: 'org.h2.Driver',
+            jdbcUrl: 'jdbc:h2:mem:demo-db',
+            user: 'sa',
+            password: '',
+            tablesOnly: true
+        };
+
+        function _loadPresets() {
+            try {
+                const restoredPresets = JSON.parse(localStorage.dbPresets);
+
+                _.forEach(restoredPresets, (restoredPreset) => {
+                    const preset = _.find(_dbPresets, {jdbcDriverClass: restoredPreset.jdbcDriverClass});
+
+                    if (preset) {
+                        preset.jdbcUrl = restoredPreset.jdbcUrl;
+                        preset.user = restoredPreset.user;
+                    }
+                });
+            }
+            catch (ignore) {
+                // No-op.
+            }
+        }
+
+        _loadPresets();
+
+        function _savePreset(preset) {
+            try {
+                const oldPreset = _.find(_dbPresets, {jdbcDriverClass: preset.jdbcDriverClass});
+
+                if (oldPreset)
+                    angular.extend(oldPreset, preset);
+                else
+                    _dbPresets.push(preset);
+
+                localStorage.dbPresets = JSON.stringify(_dbPresets);
+            }
+            catch (err) {
+                Messages.showError(err);
+            }
+        }
+
+        function _findPreset(selectedJdbcJar) {
+            let result = _.find(_dbPresets, function(preset) {
+                return preset.jdbcDriverClass === selectedJdbcJar.jdbcDriverClass;
+            });
+
+            if (!result)
+                result = {db: 'General', jdbcUrl: 'jdbc:[database]', user: 'admin'};
+
+            result.jdbcDriverJar = selectedJdbcJar.jdbcDriverJar;
+            result.jdbcDriverClass = selectedJdbcJar.jdbcDriverClass;
+
+            return result;
+        }
+
+        $scope.$watch('ui.selectedJdbcDriverJar', function(val) {
+            if (val && !$scope.importDomain.demo) {
+                const foundPreset = _findPreset(val);
+
+                const selectedPreset = $scope.selectedPreset;
+
+                selectedPreset.db = foundPreset.db;
+                selectedPreset.jdbcDriverJar = foundPreset.jdbcDriverJar;
+                selectedPreset.jdbcDriverClass = foundPreset.jdbcDriverClass;
+                selectedPreset.jdbcUrl = foundPreset.jdbcUrl;
+                selectedPreset.user = foundPreset.user;
+            }
+        }, true);
+
+        $scope.ui.showValid = true;
+
+        $scope.supportedJdbcTypes = LegacyUtils.mkOptions(LegacyUtils.SUPPORTED_JDBC_TYPES);
+
+        $scope.supportedJavaTypes = LegacyUtils.mkOptions(LegacyUtils.javaBuiltInTypes);
+
+        $scope.sortDirections = [
+            {value: true, label: 'ASC'},
+            {value: false, label: 'DESC'}
+        ];
+
+        $scope.domains = [];
+
+        $scope.isJavaBuiltInClass = function() {
+            const item = $scope.backupItem;
+
+            if (item && item.keyType)
+                return LegacyUtils.isJavaBuiltInClass(item.keyType);
+
+            return false;
+        };
+
+        $scope.selectAllSchemas = function() {
+            const allSelected = $scope.importDomain.allSchemasSelected;
+
+            _.forEach($scope.importDomain.displayedSchemas, (schema) => {
+                schema.use = allSelected;
+            });
+        };
+
+        $scope.selectSchema = function() {
+            if (LegacyUtils.isDefined($scope.importDomain) && LegacyUtils.isDefined($scope.importDomain.displayedSchemas))
+                $scope.importDomain.allSchemasSelected = $scope.importDomain.displayedSchemas.length > 0 && _.every($scope.importDomain.displayedSchemas, 'use', true);
+        };
+
+        $scope.selectAllTables = function() {
+            const allSelected = $scope.importDomain.allTablesSelected;
+
+            _.forEach($scope.importDomain.displayedTables, function(table) {
+                table.use = allSelected;
+            });
+        };
+
+        $scope.selectTable = function() {
+            if (LegacyUtils.isDefined($scope.importDomain) && LegacyUtils.isDefined($scope.importDomain.displayedTables))
+                $scope.importDomain.allTablesSelected = $scope.importDomain.displayedTables.length > 0 && _.every($scope.importDomain.displayedTables, 'use', true);
+        };
+
+        $scope.$watch('importDomain.displayedSchemas', $scope.selectSchema);
+
+        $scope.$watch('importDomain.displayedTables', $scope.selectTable);
+
+        // Pre-fetch modal dialogs.
+        const importDomainModal = $modal({scope: $scope, templateUrl: '/configuration/domains-import.html', show: false});
+
+        const hideImportDomain = importDomainModal.hide;
+
+        importDomainModal.hide = function() {
+            IgniteAgentMonitor.stopWatch();
+
+            hideImportDomain();
+        };
+
+        $scope.linkId = () => $scope.backupItem._id ? $scope.backupItem._id : 'create';
+
+        function prepareNewItem(cacheId) {
+            return {
+                space: $scope.spaces[0]._id,
+                caches: cacheId && _.find($scope.caches, {value: cacheId}) ? [cacheId] : // eslint-disable-line no-nested-ternary
+                    (_.isEmpty($scope.caches) ? [] : [$scope.caches[0].value]),
+                queryMetadata: 'Configuration'
+            };
+        }
+
+        /**
+         * Show import domain models modal.
+         */
+        $scope.showImportDomainModal = function() {
+            LegacyTable.tableReset();
+
+            FormUtils.confirmUnsavedChanges($scope.ui.inputForm.$dirty, function() {
+                if ($scope.ui.inputForm.$dirty)
+                    $scope.backupItem = $scope.selectedItem ? angular.copy($scope.selectedItem) : prepareNewItem();
+
+                const demo = $root.IgniteDemoMode;
+
+                $scope.importDomain = {
+                    demo,
+                    action: demo ? 'connect' : 'drivers',
+                    jdbcDriversNotFound: demo,
+                    schemas: [],
+                    allSchemasSelected: false,
+                    tables: [],
+                    allTablesSelected: false,
+                    button: 'Next',
+                    info: ''
+                };
+
+                $scope.importDomain.loadingOptions = LOADING_JDBC_DRIVERS;
+
+                IgniteAgentMonitor.startWatch({text: 'Back to Domain models', goal: 'import domain model from database'})
+                    .then(importDomainModal.$promise)
+                    .then(importDomainModal.show)
+                    .then(() => {
+                        if (demo) {
+                            $scope.ui.packageNameUserInput = $scope.ui.packageName;
+                            $scope.ui.packageName = 'model';
+
+                            return;
+                        }
+
+                        // Get available JDBC drivers via agent.
+                        Loading.start('importDomainFromDb');
+
+                        $scope.jdbcDriverJars = [];
+                        $scope.ui.selectedJdbcDriverJar = {};
+
+                        return IgniteAgentMonitor.drivers()
+                            .then((drivers) => {
+                                $scope.ui.packageName = $scope.ui.packageNameUserInput;
+
+                                if (drivers && drivers.length > 0) {
+                                    drivers = _.sortBy(drivers, 'jdbcDriverJar');
+
+                                    _.forEach(drivers, (drv) => {
+                                        $scope.jdbcDriverJars.push({
+                                            label: drv.jdbcDriverJar,
+                                            value: {
+                                                jdbcDriverJar: drv.jdbcDriverJar,
+                                                jdbcDriverClass: drv.jdbcDriverCls
+                                            }
+                                        });
+                                    });
+
+                                    $scope.ui.selectedJdbcDriverJar = $scope.jdbcDriverJars[0].value;
+
+                                    FormUtils.confirmUnsavedChanges($scope.ui.inputForm.$dirty, () => {
+                                        $scope.importDomain.action = 'connect';
+                                        $scope.importDomain.tables = [];
+
+                                        Focus.move('jdbcUrl');
+                                    });
+                                }
+                                else {
+                                    $scope.importDomain.jdbcDriversNotFound = true;
+                                    $scope.importDomain.button = 'Cancel';
+                                }
+                            })
+                            .then(() => {
+                                $scope.importDomain.info = INFO_CONNECT_TO_DB;
+
+                                Loading.finish('importDomainFromDb');
+                            });
+                    });
+            });
+        };
+
+        /**
+         * Load list of database schemas.
+         */
+        function _loadSchemas() {
+            IgniteAgentMonitor.awaitAgent()
+                .then(function() {
+                    $scope.importDomain.loadingOptions = LOADING_SCHEMAS;
+                    Loading.start('importDomainFromDb');
+
+                    if ($root.IgniteDemoMode)
+                        return IgniteAgentMonitor.schemas($scope.demoConnection);
+
+                    const preset = $scope.selectedPreset;
+
+                    _savePreset(preset);
+
+                    return IgniteAgentMonitor.schemas(preset);
+                })
+                .then(function(schemas) {
+                    $scope.importDomain.schemas = _.map(schemas, function(schema) {
+                        return {use: true, name: schema};
+                    });
+
+                    $scope.importDomain.action = 'schemas';
+
+                    if ($scope.importDomain.schemas.length === 0)
+                        $scope.importDomainNext();
+
+                    $scope.importDomain.info = INFO_SELECT_SCHEMAS;
+                })
+                .catch(Messages.showError)
+                .then(() => Loading.finish('importDomainFromDb'));
+        }
+
+        const DFLT_PARTITIONED_CACHE = {
+            label: 'PARTITIONED',
+            value: -1,
+            cache: {
+                name: 'PARTITIONED',
+                cacheMode: 'PARTITIONED',
+                atomicityMode: 'ATOMIC',
+                readThrough: true,
+                writeThrough: true
+            }
+        };
+
+        const DFLT_REPLICATED_CACHE = {
+            label: 'REPLICATED',
+            value: -2,
+            cache: {
+                name: 'REPLICATED',
+                cacheMode: 'REPLICATED',
+                atomicityMode: 'ATOMIC',
+                readThrough: true,
+                writeThrough: true
+            }
+        };
+
+        let _importCachesOrTemplates = [];
+
+        $scope.tableActionView = function(tbl) {
+            const cacheName = _.find(_importCachesOrTemplates, {value: tbl.cacheOrTemplate}).label;
+
+            if (tbl.action === IMPORT_DM_NEW_CACHE)
+                return 'Create ' + tbl.generatedCacheName + ' (' + cacheName + ')';
+
+            return 'Associate with ' + cacheName;
+        };
+
+        function toJavaClassName(name) {
+            const len = name.length;
+
+            let buf = '';
+
+            let capitalizeNext = true;
+
+            for (let i = 0; i < len; i++) {
+                const ch = name.charAt(i);
+
+                if (ch === ' ' || ch === '_')
+                    capitalizeNext = true;
+                else if (capitalizeNext) {
+                    buf += ch.toLocaleUpperCase();
+
+                    capitalizeNext = false;
+                }
+                else
+                    buf += ch.toLocaleLowerCase();
+            }
+
+            return buf;
+        }
+
+        function toJavaName(dbName) {
+            const javaName = toJavaClassName(dbName);
+
+            return javaName.charAt(0).toLocaleLowerCase() + javaName.slice(1);
+        }
+
+        function _fillCommonCachesOrTemplates(item) {
+            return function(action) {
+                if (item.cachesOrTemplates)
+                    item.cachesOrTemplates.length = 0;
+                else
+                    item.cachesOrTemplates = [];
+
+                if (action === IMPORT_DM_NEW_CACHE) {
+                    item.cachesOrTemplates.push(DFLT_PARTITIONED_CACHE);
+                    item.cachesOrTemplates.push(DFLT_REPLICATED_CACHE);
+                }
+
+                if (!_.isEmpty($scope.caches)) {
+                    if (item.cachesOrTemplates.length > 0)
+                        item.cachesOrTemplates.push(null);
+
+                    _.forEach($scope.caches, function(cache) {
+                        item.cachesOrTemplates.push(cache);
+                    });
+                }
+
+                if (!_.find(item.cachesOrTemplates, {value: item.cacheOrTemplate}))
+                    item.cacheOrTemplate = item.cachesOrTemplates[0].value;
+            };
+        }
+        /**
+         * Load list of database tables.
+         */
+        function _loadTables() {
+            IgniteAgentMonitor.awaitAgent()
+                .then(function() {
+                    $scope.importDomain.loadingOptions = LOADING_TABLES;
+                    Loading.start('importDomainFromDb');
+
+                    $scope.importDomain.allTablesSelected = false;
+
+                    const preset = $scope.importDomain.demo ? $scope.demoConnection : $scope.selectedPreset;
+
+                    preset.schemas = [];
+
+                    _.forEach($scope.importDomain.schemas, function(schema) {
+                        if (schema.use)
+                            preset.schemas.push(schema.name);
+                    });
+
+                    return IgniteAgentMonitor.tables(preset);
+                })
+                .then(function(tables) {
+                    _importCachesOrTemplates = [DFLT_PARTITIONED_CACHE, DFLT_REPLICATED_CACHE].concat($scope.caches);
+
+                    _fillCommonCachesOrTemplates($scope.importCommon)($scope.importCommon.action);
+
+                    _.forEach(tables, function(tbl, idx) {
+                        tbl.id = idx;
+                        tbl.action = IMPORT_DM_NEW_CACHE;
+                        tbl.generatedCacheName = toJavaClassName(tbl.tbl) + 'Cache';
+                        tbl.cacheOrTemplate = DFLT_PARTITIONED_CACHE.value;
+                        tbl.label = tbl.schema + '.' + tbl.tbl;
+                        tbl.edit = false;
+                        tbl.use = LegacyUtils.isDefined(_.find(tbl.cols, function(col) {
+                            return col.key;
+                        }));
+                    });
+
+                    $scope.importDomain.action = 'tables';
+                    $scope.importDomain.tables = tables;
+                    $scope.importDomain.info = INFO_SELECT_TABLES;
+                })
+                .catch(Messages.showError)
+                .then(() => Loading.finish('importDomainFromDb'));
+        }
+
+        $scope.applyDefaults = function() {
+            _.forEach($scope.importDomain.displayedTables, function(table) {
+                table.edit = false;
+                table.action = $scope.importCommon.action;
+                table.cacheOrTemplate = $scope.importCommon.cacheOrTemplate;
+            });
+        };
+
+        $scope._curDbTable = null;
+
+        $scope.startEditDbTableCache = function(tbl) {
+            if ($scope._curDbTable) {
+                $scope._curDbTable.edit = false;
+
+                if ($scope._curDbTable.actionWatch) {
+                    $scope._curDbTable.actionWatch();
+
+                    $scope._curDbTable.actionWatch = null;
+                }
+            }
+
+            $scope._curDbTable = tbl;
+
+            const _fillFn = _fillCommonCachesOrTemplates($scope._curDbTable);
+
+            _fillFn($scope._curDbTable.action);
+
+            $scope._curDbTable.actionWatch = $scope.$watch('_curDbTable.action', _fillFn, true);
+
+            $scope._curDbTable.edit = true;
+        };
+
+        /**
+         * Show page with import domain models options.
+         */
+        function _selectOptions() {
+            $scope.importDomain.action = 'options';
+            $scope.importDomain.button = 'Save';
+            $scope.importDomain.info = INFO_SELECT_OPTIONS;
+
+            Focus.move('domainPackageName');
+        }
+
+        function _saveBatch(batch) {
+            if (batch && batch.length > 0) {
+                $scope.importDomain.loadingOptions = SAVING_DOMAINS;
+                Loading.start('importDomainFromDb');
+
+                $http.post('/api/v1/configuration/domains/save/batch', batch)
+                    .success(function(savedBatch) {
+                        let lastItem;
+                        const newItems = [];
+
+                        _.forEach(_mapCaches(savedBatch.generatedCaches), function(cache) {
+                            $scope.caches.push(cache);
+                        });
+
+                        _.forEach(savedBatch.savedDomains, function(savedItem) {
+                            const idx = _.findIndex($scope.domains, function(domain) {
+                                return domain._id === savedItem._id;
+                            });
+
+                            if (idx >= 0)
+                                $scope.domains[idx] = savedItem;
+                            else
+                                newItems.push(savedItem);
+
+                            lastItem = savedItem;
+                        });
+
+                        _.forEach(newItems, function(item) {
+                            $scope.domains.push(item);
+                        });
+
+                        if (!lastItem && $scope.domains.length > 0)
+                            lastItem = $scope.domains[0];
+
+                        $scope.selectItem(lastItem);
+
+                        Messages.showInfo('Domain models imported from database.');
+
+                        $scope.ui.activePanels = [0, 1, 2];
+
+                        $scope.ui.showValid = true;
+                    })
+                    .error(Messages.showError)
+                    .finally(() => {
+                        Loading.finish('importDomainFromDb');
+
+                        importDomainModal.hide();
+                    });
+            }
+            else
+                importDomainModal.hide();
+        }
+
+        function _saveDomainModel() {
+            if (LegacyUtils.isEmptyString($scope.ui.packageName)) {
+                ErrorPopover.show('domainPackageNameInput', 'Package could not be empty');
+
+                Focus.move('domainPackageNameInput');
+
+                return false;
+            }
+
+            if (!LegacyUtils.isValidJavaClass('Package', $scope.ui.packageName, false, 'domainPackageNameInput', true)) {
+                Focus.move('domainPackageNameInput');
+
+                return false;
+            }
+
+            const batch = [];
+            const checkedCaches = [];
+
+            let containKey = true;
+            let containDup = false;
+
+            function queryField(name, jdbcType) {
+                return {name: toJavaName(name), className: jdbcType.javaType};
+            }
+
+            function dbField(name, jdbcType, nullable) {
+                return {
+                    jdbcType,
+                    databaseFieldName: name,
+                    databaseFieldType: jdbcType.dbName,
+                    javaFieldName: toJavaName(name),
+                    javaFieldType: nullable ? jdbcType.javaType :
+                        ($scope.ui.usePrimitives && jdbcType.primitiveType ? jdbcType.primitiveType : jdbcType.javaType)
+                };
+            }
+
+            _.forEach($scope.importDomain.tables, function(table, curIx) {
+                if (table.use) {
+                    const qryFields = [];
+                    const indexes = [];
+                    const keyFields = [];
+                    const valFields = [];
+                    const aliases = [];
+
+                    const tableName = table.tbl;
+                    let typeName = toJavaClassName(tableName);
+
+                    if (_.find($scope.importDomain.tables,
+                            (tbl, ix) => tbl.use && ix !== curIx && tableName === tbl.tbl)) {
+                        typeName = typeName + '_' + toJavaClassName(table.schema);
+
+                        containDup = true;
+                    }
+
+                    const valType = _toJavaPackage($scope.ui.packageName) + '.' + typeName;
+
+                    let _containKey = false;
+
+                    _.forEach(table.cols, function(col) {
+                        const colName = col.name;
+                        const jdbcType = LegacyUtils.findJdbcType(col.type);
+                        const nullable = col.nullable;
+
+                        qryFields.push(queryField(colName, jdbcType));
+
+                        const fld = dbField(colName, jdbcType, nullable);
+
+                        if ($scope.ui.generateAliases && !_.find(aliases, {field: fld.javaFieldName}) &&
+                            fld.javaFieldName.toUpperCase() !== fld.databaseFieldName.toUpperCase())
+                            aliases.push({field: fld.javaFieldName, alias: fld.databaseFieldName});
+
+                        if (col.key) {
+                            keyFields.push(fld);
+
+                            _containKey = true;
+                        }
+                        else
+                            valFields.push(fld);
+                    });
+
+                    containKey &= _containKey;
+
+                    if (table.idxs) {
+                        _.forEach(table.idxs, function(idx) {
+                            const fields = Object.keys(idx.fields);
+
+                            indexes.push({
+                                name: idx.name, indexType: 'SORTED', fields: _.map(fields, function(fieldName) {
+                                    return {
+                                        name: toJavaName(fieldName),
+                                        direction: idx.fields[fieldName]
+                                    };
+                                })
+                            });
+                        });
+                    }
+
+                    const domainFound = _.find($scope.domains, function(domain) {
+                        return domain.valueType === valType;
+                    });
+
+                    const newDomain = {
+                        confirm: false,
+                        skip: false,
+                        space: $scope.spaces[0],
+                        caches: []
+                    };
+
+                    if (LegacyUtils.isDefined(domainFound)) {
+                        newDomain._id = domainFound._id;
+                        newDomain.caches = domainFound.caches;
+                        newDomain.confirm = true;
+                    }
+
+                    newDomain.keyType = valType + 'Key';
+                    newDomain.valueType = valType;
+                    newDomain.queryMetadata = 'Configuration';
+                    newDomain.databaseSchema = table.schema;
+                    newDomain.databaseTable = tableName;
+                    newDomain.fields = qryFields;
+                    newDomain.indexes = indexes;
+                    newDomain.keyFields = keyFields;
+                    newDomain.aliases = aliases;
+                    newDomain.valueFields = valFields;
+
+                    // If value fields not found - copy key fields.
+                    if (_.isEmpty(valFields))
+                        newDomain.valueFields = keyFields.slice();
+
+                    // Use Java built-in type for key.
+                    if ($scope.ui.builtinKeys && newDomain.keyFields.length === 1) {
+                        const keyField = newDomain.keyFields[0];
+
+                        newDomain.keyType = keyField.jdbcType.javaType;
+
+                        // Exclude key column from query fields and indexes.
+                        newDomain.fields = _.filter(newDomain.fields, function(field) {
+                            return field.name !== keyField.javaFieldName;
+                        });
+
+                        _.forEach(newDomain.indexes, function(index) {
+                            index.fields = _.filter(index.fields, function(field) {
+                                return field.name !== keyField.javaFieldName;
+                            });
+                        });
+
+                        newDomain.indexes = _.filter(newDomain.indexes, (index) => !_.isEmpty(index.fields));
+                    }
+
+                    // Prepare caches for generation.
+                    if (table.action === IMPORT_DM_NEW_CACHE) {
+                        const template = _.find(_importCachesOrTemplates, {value: table.cacheOrTemplate});
+
+                        const newCache = angular.copy(template.cache);
+
+                        newDomain.newCache = newCache;
+
+                        delete newCache._id;
+                        newCache.name = typeName + 'Cache';
+                        newCache.clusters = $scope.ui.generatedCachesClusters;
+
+                        // POJO store factory is not defined in template.
+                        if (!newCache.cacheStoreFactory || newCache.cacheStoreFactory.kind !== 'CacheJdbcPojoStoreFactory') {
+                            const dialect = $scope.importDomain.demo ? 'H2' : $scope.selectedPreset.db;
+
+                            newCache.cacheStoreFactory = {
+                                kind: 'CacheJdbcPojoStoreFactory',
+                                CacheJdbcPojoStoreFactory: {dataSourceBean: 'ds' + dialect, dialect},
+                                CacheJdbcBlobStoreFactory: { connectVia: 'DataSource' }
+                            };
+                        }
+
+                        if (!newCache.readThrough && !newCache.writeThrough) {
+                            newCache.readThrough = true;
+                            newCache.writeThrough = true;
+                        }
+                    }
+                    else {
+                        const cacheId = table.cacheOrTemplate;
+
+                        newDomain.caches = [cacheId];
+
+                        if (!_.includes(checkedCaches, cacheId)) {
+                            const cache = _.find($scope.caches, {value: cacheId}).cache;
+
+                            const change = LegacyUtils.autoCacheStoreConfiguration(cache, [newDomain]);
+
+                            if (change)
+                                newDomain.cacheStoreChanges = [{cacheId, change}];
+
+                            checkedCaches.push(cacheId);
+                        }
+                    }
+
+                    batch.push(newDomain);
+                }
+            });
+
+            /**
+             * Generate message to show on confirm dialog.
+             *
+             * @param meta Object to confirm.
+             * @returns {string} Generated message.
+             */
+            function overwriteMessage(meta) {
+                return '<span>' +
+                    'Domain model with name &quot;' + meta.databaseTable + '&quot; already exist.<br/><br/>' +
+                    'Are you sure you want to overwrite it?' +
+                    '</span>';
+            }
+
+            const itemsToConfirm = _.filter(batch, (item) => item.confirm);
+
+            function checkOverwrite() {
+                if (itemsToConfirm.length > 0) {
+                    ConfirmBatch.confirm(overwriteMessage, itemsToConfirm)
+                        .then(() => _saveBatch(_.filter(batch, (item) => !item.skip)))
+                        .catch(() => Messages.showError('Importing of domain models interrupted by user.'));
+                }
+                else
+                    _saveBatch(batch);
+            }
+
+            function checkDuplicate() {
+                if (containDup) {
+                    Confirm.confirm('Some tables have the same name.<br/>' +
+                            'Name of types for that tables will contain schema name too.')
+                        .then(() => checkOverwrite());
+                }
+                else
+                    checkOverwrite();
+            }
+
+            if (containKey)
+                checkDuplicate();
+            else {
+                Confirm.confirm('Some tables have no primary key.<br/>' +
+                        'You will need to configure key type and key fields for such tables after import complete.')
+                    .then(() => checkDuplicate());
+            }
+        }
+
+        $scope.importDomainNext = function() {
+            if (!$scope.importDomainNextAvailable())
+                return;
+
+            const act = $scope.importDomain.action;
+
+            if (act === 'drivers' && $scope.importDomain.jdbcDriversNotFound)
+                importDomainModal.hide();
+            else if (act === 'connect')
+                _loadSchemas();
+            else if (act === 'schemas')
+                _loadTables();
+            else if (act === 'tables')
+                _selectOptions();
+            else if (act === 'options')
+                _saveDomainModel();
+        };
+
+        $scope.nextTooltipText = function() {
+            const importDomainNextAvailable = $scope.importDomainNextAvailable();
+
+            const act = $scope.importDomain.action;
+
+            if (act === 'drivers' && $scope.importDomain.jdbcDriversNotFound)
+                return 'Resolve issue with JDBC drivers<br>Close this dialog and try again';
+
+            if (act === 'connect' && _.isNil($scope.selectedPreset.jdbcDriverClass))
+                return 'Input valid JDBC driver class name';
+
+            if (act === 'connect' && _.isNil($scope.selectedPreset.jdbcUrl))
+                return 'Input valid JDBC URL';
+
+            if (act === 'connect' || act === 'drivers')
+                return 'Click to load list of schemas from database';
+
+            if (act === 'schemas')
+                return importDomainNextAvailable ? 'Click to load list of tables from database' : 'Select schemas to continue';
+
+            if (act === 'tables')
+                return importDomainNextAvailable ? 'Click to show import options' : 'Select tables to continue';
+
+            if (act === 'options')
+                return 'Click to import domain model for selected tables';
+
+            return 'Click to continue';
+        };
+
+        $scope.prevTooltipText = function() {
+            const act = $scope.importDomain.action;
+
+            if (act === 'schemas')
+                return $scope.importDomain.demo ? 'Click to return on demo description step' : 'Click to return on connection configuration step';
+
+            if (act === 'tables')
+                return 'Click to return on schemas selection step';
+
+            if (act === 'options')
+                return 'Click to return on tables selection step';
+        };
+
+        $scope.importDomainNextAvailable = function() {
+            switch ($scope.importDomain.action) {
+                case 'connect':
+                    return !_.isNil($scope.selectedPreset.jdbcDriverClass) && !_.isNil($scope.selectedPreset.jdbcUrl);
+
+                case 'schemas':
+                    return _.isEmpty($scope.importDomain.schemas) || _.find($scope.importDomain.schemas, {use: true});
+
+                case 'tables':
+                    return _.find($scope.importDomain.tables, {use: true});
+
+                default:
+                    return true;
+            }
+        };
+
+        $scope.importDomainPrev = function() {
+            $scope.importDomain.button = 'Next';
+
+            if ($scope.importDomain.action === 'options') {
+                $scope.importDomain.action = 'tables';
+                $scope.importDomain.info = INFO_SELECT_TABLES;
+            }
+            else if ($scope.importDomain.action === 'tables' && $scope.importDomain.schemas.length > 0) {
+                $scope.importDomain.action = 'schemas';
+                $scope.importDomain.info = INFO_SELECT_SCHEMAS;
+            }
+            else {
+                $scope.importDomain.action = 'connect';
+                $scope.importDomain.info = INFO_CONNECT_TO_DB;
+            }
+        };
+
+        $scope.domainModelTitle = function() {
+            return $scope.ui.showValid ? 'Domain model types:' : 'Domain model types without key fields:';
+        };
+
+        function selectFirstItem() {
+            if ($scope.domains.length > 0)
+                $scope.selectItem($scope.domains[0]);
+        }
+
+        $scope.importActions = [{
+            label: 'Create new cache by template',
+            shortLabel: 'Create',
+            value: IMPORT_DM_NEW_CACHE
+        }];
+
+        $scope.importCommon = {};
+
+        // When landing on the page, get domain models and show them.
+        Loading.start('loadingDomainModelsScreen');
+
+        Resource.read()
+            .then(({spaces, clusters, caches, domains}) => {
+                $scope.spaces = spaces;
+                $scope.clusters = _.map(clusters, (cluster) => ({
+                    label: cluster.name,
+                    value: cluster._id
+                }));
+                $scope.caches = _mapCaches(caches);
+                $scope.domains = _.sortBy(domains, 'valueType');
+
+                _.forEach($scope.clusters, (cluster) => $scope.ui.generatedCachesClusters.push(cluster.value));
+
+                if (!_.isEmpty($scope.caches)) {
+                    $scope.importActions.push({
+                        label: 'Associate with existing cache',
+                        shortLabel: 'Associate',
+                        value: IMPORT_DM_ASSOCIATE_CACHE
+                    });
+                }
+
+                $scope.$watch('importCommon.action', _fillCommonCachesOrTemplates($scope.importCommon), true);
+
+                $scope.importCommon.action = IMPORT_DM_NEW_CACHE;
+
+                if ($state.params.linkId)
+                    $scope.createItem($state.params.linkId);
+                else {
+                    const lastSelectedDomain = angular.fromJson(sessionStorage.lastSelectedDomain);
+
+                    if (lastSelectedDomain) {
+                        const idx = _.findIndex($scope.domains, function(domain) {
+                            return domain._id === lastSelectedDomain;
+                        });
+
+                        if (idx >= 0)
+                            $scope.selectItem($scope.domains[idx]);
+                        else {
+                            sessionStorage.removeItem('lastSelectedDomain');
+
+                            selectFirstItem();
+                        }
+                    }
+                    else
+                        selectFirstItem();
+                }
+
+                $scope.$watch('ui.inputForm.$valid', function(valid) {
+                    if (valid && ModelNormalizer.isEqual(__original_value, $scope.backupItem))
+                        $scope.ui.inputForm.$dirty = false;
+                });
+
+                $scope.$watch('backupItem', function(val) {
+                    if (!$scope.ui.inputForm)
+                        return;
+
+                    const form = $scope.ui.inputForm;
+
+                    if (form.$valid && ModelNormalizer.isEqual(__original_value, val))
+                        form.$setPristine();
+                    else
+                        form.$setDirty();
+                }, true);
+
+                $scope.$watch('ui.activePanels.length', () => {
+                    ErrorPopover.hide();
+                });
+            })
+            .catch(Messages.showError)
+            .then(() => {
+                $scope.ui.ready = true;
+                $scope.ui.inputForm && $scope.ui.inputForm.$setPristine();
+
+                Loading.finish('loadingDomainModelsScreen');
+            });
+
+        const clearFormDefaults = (ngFormCtrl) => {
+            if (!ngFormCtrl)
+                return;
+
+            ngFormCtrl.$defaults = {};
+
+            _.forOwn(ngFormCtrl, (value, key) => {
+                if (value && key !== '$$parentForm' && value.constructor.name === 'FormController')
+                    clearFormDefaults(value);
+            });
+        };
+
+        $scope.selectItem = function(item, backup) {
+            function selectItem() {
+                clearFormDefaults($scope.ui.inputForm);
+
+                LegacyTable.tableReset();
+
+                $scope.selectedItem = item;
+
+                try {
+                    if (item && item._id)
+                        sessionStorage.lastSelectedDomain = angular.toJson(item._id);
+                    else
+                        sessionStorage.removeItem('lastSelectedDomain');
+                }
+                catch (ignored) {
+                    // Ignore possible errors when read from storage.
+                }
+
+                if (backup)
+                    $scope.backupItem = backup;
+                else if (item)
+                    $scope.backupItem = angular.copy(item);
+                else
+                    $scope.backupItem = emptyDomain;
+
+                $scope.backupItem = angular.merge({}, blank, $scope.backupItem);
+
+                if ($scope.ui.inputForm) {
+                    $scope.ui.inputForm.$error = {};
+                    $scope.ui.inputForm.$setPristine();
+                }
+
+                __original_value = ModelNormalizer.normalize($scope.backupItem);
+
+                if (LegacyUtils.isDefined($scope.backupItem) && !LegacyUtils.isDefined($scope.backupItem.queryMetadata))
+                    $scope.backupItem.queryMetadata = 'Configuration';
+
+                if (LegacyUtils.isDefined($scope.selectedItem) && !LegacyUtils.isDefined($scope.selectedItem.queryMetadata))
+                    $scope.selectedItem.queryMetadata = 'Configuration';
+
+                if (LegacyUtils.getQueryVariable('new'))
+                    $state.go('base.configuration.domains');
+            }
+
+            FormUtils.confirmUnsavedChanges($scope.backupItem && $scope.ui.inputForm && $scope.ui.inputForm.$dirty, selectItem);
+        };
+
+        // Add new domain model.
+        $scope.createItem = function(cacheId) {
+            if ($scope.tableReset(true)) {
+                $timeout(() => {
+                    FormUtils.ensureActivePanel($scope.ui, 'query');
+                    FormUtils.ensureActivePanel($scope.ui, 'general', 'keyTypeInput');
+                });
+
+                $scope.selectItem(null, prepareNewItem(cacheId));
+            }
+        };
+
+        function checkQueryConfiguration(item) {
+            if (item.queryMetadata === 'Configuration' && LegacyUtils.domainForQueryConfigured(item)) {
+                if (_.isEmpty(item.fields))
+                    return ErrorPopover.show('queryFields', 'Query fields should not be empty', $scope.ui, 'query');
+
+                const indexes = item.indexes;
+
+                if (indexes && indexes.length > 0) {
+                    if (_.find(indexes, function(index, i) {
+                        if (_.isEmpty(index.fields))
+                            return !ErrorPopover.show('indexes' + i, 'Index fields are not specified', $scope.ui, 'query');
+                    }))
+                        return false;
+                }
+            }
+
+            return true;
+        }
+
+        function checkStoreConfiguration(item) {
+            if (LegacyUtils.domainForStoreConfigured(item)) {
+                if (LegacyUtils.isEmptyString(item.databaseSchema))
+                    return ErrorPopover.show('databaseSchemaInput', 'Database schema should not be empty', $scope.ui, 'store');
+
+                if (LegacyUtils.isEmptyString(item.databaseTable))
+                    return ErrorPopover.show('databaseTableInput', 'Database table should not be empty', $scope.ui, 'store');
+
+                if (_.isEmpty(item.keyFields))
+                    return ErrorPopover.show('keyFields', 'Key fields are not specified', $scope.ui, 'store');
+
+                if (LegacyUtils.isJavaBuiltInClass(item.keyType) && item.keyFields.length !== 1)
+                    return ErrorPopover.show('keyFields', 'Only one field should be specified in case when key type is a Java built-in type', $scope.ui, 'store');
+
+                if (_.isEmpty(item.valueFields))
+                    return ErrorPopover.show('valueFields', 'Value fields are not specified', $scope.ui, 'store');
+            }
+
+            return true;
+        }
+
+        // Check domain model logical consistency.
+        function validate(item) {
+            if (!LegacyUtils.checkFieldValidators($scope.ui))
+                return false;
+
+            if (!checkQueryConfiguration(item))
+                return false;
+
+            if (!checkStoreConfiguration(item))
+                return false;
+
+            if (!LegacyUtils.domainForStoreConfigured(item) && !LegacyUtils.domainForQueryConfigured(item) && item.queryMetadata === 'Configuration')
+                return ErrorPopover.show('query-title', 'SQL query domain model should be configured', $scope.ui, 'query');
+
+            return true;
+        }
+
+        function _checkShowValidPresentation() {
+            if (!$scope.ui.showValid) {
+                const validFilter = $filter('domainsValidation');
+
+                $scope.ui.showValid = validFilter($scope.domains, false, true).length === 0;
+            }
+        }
+
+        // Save domain models into database.
+        function save(item) {
+            const qry = LegacyUtils.domainForQueryConfigured(item);
+            const str = LegacyUtils.domainForStoreConfigured(item);
+
+            item.kind = 'query';
+
+            if (qry && str)
+                item.kind = 'both';
+            else if (str)
+                item.kind = 'store';
+
+            $http.post('/api/v1/configuration/domains/save', item)
+                .success(function(res) {
+                    $scope.ui.inputForm.$setPristine();
+
+                    const savedMeta = res.savedDomains[0];
+
+                    const idx = _.findIndex($scope.domains, function(domain) {
+                        return domain._id === savedMeta._id;
+                    });
+
+                    if (idx >= 0)
+                        angular.extend($scope.domains[idx], savedMeta);
+                    else
+                        $scope.domains.push(savedMeta);
+
+                    _.forEach($scope.caches, (cache) => {
+                        if (_.includes(item.caches, cache.value))
+                            cache.cache.domains = _.union(cache.cache.domains, [savedMeta._id]);
+                        else
+                            _.remove(cache.cache.domains, (id) => id === savedMeta._id);
+                    });
+
+                    $scope.selectItem(savedMeta);
+
+                    Messages.showInfo('Domain model "' + item.valueType + '" saved.');
+
+                    _checkShowValidPresentation();
+                })
+                .error(Messages.showError);
+        }
+
+        // Save domain model.
+        $scope.saveItem = function() {
+            if ($scope.tableReset(true)) {
+                const item = $scope.backupItem;
+
+                item.cacheStoreChanges = [];
+
+                _.forEach(item.caches, function(cacheId) {
+                    const cache = _.find($scope.caches, {value: cacheId}).cache;
+
+                    const change = LegacyUtils.autoCacheStoreConfiguration(cache, [item]);
+
+                    if (change)
+                        item.cacheStoreChanges.push({cacheId, change});
+                });
+
+                if (validate(item))
+                    save(item);
+            }
+        };
+
+        function _domainNames() {
+            return _.map($scope.domains, function(domain) {
+                return domain.valueType;
+            });
+        }
+
+        function _newNameIsValidJavaClass(newName) {
+            return LegacyUtils.isValidJavaClass('New name for value type', newName, false, 'copy-new-nameInput');
+        }
+
+        // Save domain model with new name.
+        $scope.cloneItem = function() {
+            if ($scope.tableReset(true) && validate($scope.backupItem)) {
+                Clone.confirm($scope.backupItem.valueType, _domainNames(), _newNameIsValidJavaClass).then(function(newName) {
+                    const item = angular.copy($scope.backupItem);
+
+                    delete item._id;
+                    item.valueType = newName;
+
+                    save(item);
+                });
+            }
+        };
+
+        // Remove domain model from db.
+        $scope.removeItem = function() {
+            LegacyTable.tableReset();
+
+            const selectedItem = $scope.selectedItem;
+
+            Confirm.confirm('Are you sure you want to remove domain model: "' + selectedItem.valueType + '"?')
+                .then(function() {
+                    const _id = selectedItem._id;
+
+                    $http.post('/api/v1/configuration/domains/remove', {_id})
+                        .success(function() {
+                            Messages.showInfo('Domain model has been removed: ' + selectedItem.valueType);
+
+                            const domains = $scope.domains;
+
+                            const idx = _.findIndex(domains, function(domain) {
+                                return domain._id === _id;
+                            });
+
+                            if (idx >= 0) {
+                                domains.splice(idx, 1);
+
+                                $scope.ui.inputForm.$setPristine();
+
+                                if (domains.length > 0)
+                                    $scope.selectItem(domains[0]);
+                                else
+                                    $scope.backupItem = emptyDomain;
+
+                                _.forEach($scope.caches, (cache) => _.remove(cache.cache.domains, (id) => id === _id));
+                            }
+
+                            _checkShowValidPresentation();
+                        })
+                        .error(Messages.showError);
+                });
+        };
+
+        // Remove all domain models from db.
+        $scope.removeAllItems = function() {
+            LegacyTable.tableReset();
+
+            Confirm.confirm('Are you sure you want to remove all domain models?')
+                .then(function() {
+                    $http.post('/api/v1/configuration/domains/remove/all')
+                        .success(function() {
+                            Messages.showInfo('All domain models have been removed');
+
+                            $scope.domains = [];
+
+                            _.forEach($scope.caches, (cache) => cache.cache.domains = []);
+
+                            $scope.backupItem = emptyDomain;
+                            $scope.ui.showValid = true;
+                            $scope.ui.inputForm.$error = {};
+                            $scope.ui.inputForm.$setPristine();
+                        })
+                        .error(Messages.showError);
+                });
+        };
+
+        $scope.toggleValid = function() {
+            $scope.ui.showValid = !$scope.ui.showValid;
+
+            const validFilter = $filter('domainsValidation');
+
+            let idx = -1;
+
+            if (LegacyUtils.isDefined($scope.selectedItem)) {
+                idx = _.findIndex(validFilter($scope.domains, $scope.ui.showValid, true), function(domain) {
+                    return domain._id === $scope.selectedItem._id;
+                });
+            }
+
+            if (idx === -1)
+                $scope.backupItem = emptyDomain;
+        };
+
+        const pairFields = {
+            fields: {
+                msg: 'Query field class',
+                id: 'QryField',
+                idPrefix: 'Key',
+                searchCol: 'name',
+                valueCol: 'key',
+                classValidation: true,
+                dupObjName: 'name'
+            },
+            aliases: {id: 'Alias', idPrefix: 'Value', searchCol: 'alias', valueCol: 'value', dupObjName: 'alias'}
+        };
+
+        $scope.tablePairValid = function(item, field, index, stopEdit) {
+            const pairField = pairFields[field.model];
+
+            const pairValue = LegacyTable.tablePairValue(field, index);
+
+            if (pairField) {
+                const model = item[field.model];
+
+                if (LegacyUtils.isDefined(model)) {
+                    const idx = _.findIndex(model, function(pair) {
+                        return pair[pairField.searchCol] === pairValue[pairField.valueCol];
+                    });
+
+                    // Found duplicate by key.
+                    if (idx >= 0 && idx !== index) {
+                        if (stopEdit)
+                            return false;
+
+                        return ErrorPopover.show(LegacyTable.tableFieldId(index, pairField.idPrefix + pairField.id), 'Field with such ' + pairField.dupObjName + ' already exists!', $scope.ui, 'query');
+                    }
+                }
+
+                if (pairField.classValidation && !LegacyUtils.isValidJavaClass(pairField.msg, pairValue.value, true, LegacyTable.tableFieldId(index, 'Value' + pairField.id), false, $scope.ui, 'query')) {
+                    if (stopEdit)
+                        return false;
+
+                    return LegacyTable.tableFocusInvalidField(index, 'Value' + pairField.id);
+                }
+            }
+
+            return true;
+        };
+
+        function tableDbFieldValue(field, index) {
+            return (index < 0) ? {
+                databaseFieldName: field.newDatabaseFieldName,
+                databaseFieldType: field.newDatabaseFieldType,
+                javaFieldName: field.newJavaFieldName,
+                javaFieldType: field.newJavaFieldType
+            } : {
+                databaseFieldName: field.curDatabaseFieldName,
+                databaseFieldType: field.curDatabaseFieldType,
+                javaFieldName: field.curJavaFieldName,
+                javaFieldType: field.curJavaFieldType
+            };
+        }
+
+        $scope.tableDbFieldSaveVisible = function(field, index) {
+            const dbFieldValue = tableDbFieldValue(field, index);
+
+            return LegacyUtils.isDefined(dbFieldValue.databaseFieldType) &&
+                LegacyUtils.isDefined(dbFieldValue.javaFieldType) &&
+                !LegacyUtils.isEmptyString(dbFieldValue.databaseFieldName) &&
+                !LegacyUtils.isEmptyString(dbFieldValue.javaFieldName);
+        };
+
+        const dbFieldTables = {
+            keyFields: {msg: 'Key field', id: 'KeyField'},
+            valueFields: {msg: 'Value field', id: 'ValueField'}
+        };
+
+        $scope.tableDbFieldSave = function(field, index, stopEdit) {
+            const dbFieldTable = dbFieldTables[field.model];
+
+            if (dbFieldTable) {
+                const dbFieldValue = tableDbFieldValue(field, index);
+
+                const item = $scope.backupItem;
+
+                let model = item[field.model];
+
+                if (!LegacyUtils.isValidJavaIdentifier(dbFieldTable.msg + ' java name', dbFieldValue.javaFieldName, LegacyTable.tableFieldId(index, 'JavaFieldName' + dbFieldTable.id)))
+                    return false;
+
+                if (LegacyUtils.isDefined(model)) {
+                    let idx = _.findIndex(model, function(dbMeta) {
+                        return dbMeta.databaseFieldName === dbFieldValue.databaseFieldName;
+                    });
+
+                    // Found duplicate.
+                    if (idx >= 0 && index !== idx)
+                        return ErrorPopover.show(LegacyTable.tableFieldId(index, 'DatabaseFieldName' + dbFieldTable.id), 'Field with such database name already exists!', $scope.ui, 'store');
+
+                    idx = _.findIndex(model, function(dbMeta) {
+                        return dbMeta.javaFieldName === dbFieldValue.javaFieldName;
+                    });
+
+                    // Found duplicate.
+                    if (idx >= 0 && index !== idx)
+                        return ErrorPopover.show(LegacyTable.tableFieldId(index, 'JavaFieldName' + dbFieldTable.id), 'Field with such java name already exists!', $scope.ui, 'store');
+
+                    if (index < 0)
+                        model.push(dbFieldValue);
+                    else {
+                        const dbField = model[index];
+
+                        dbField.databaseFieldName = dbFieldValue.databaseFieldName;
+                        dbField.databaseFieldType = dbFieldValue.databaseFieldType;
+                        dbField.javaFieldName = dbFieldValue.javaFieldName;
+                        dbField.javaFieldType = dbFieldValue.javaFieldType;
+                    }
+                }
+                else {
+                    model = [dbFieldValue];
+
+                    item[field.model] = model;
+                }
+
+                if (!stopEdit) {
+                    if (index < 0)
+                        LegacyTable.tableNewItem(field);
+                    else if (index < model.length - 1)
+                        LegacyTable.tableStartEdit(item, field, index + 1);
+                    else
+                        LegacyTable.tableNewItem(field);
+                }
+
+                return true;
+            }
+
+            return false;
+        };
+
+        function tableIndexName(field, index) {
+            return index < 0 ? field.newIndexName : field.curIndexName;
+        }
+
+        function tableIndexType(field, index) {
+            return index < 0 ? field.newIndexType : field.curIndexType;
+        }
+
+        $scope.tableIndexSaveVisible = function(field, index) {
+            return !LegacyUtils.isEmptyString(tableIndexName(field, index)) && LegacyUtils.isDefined(tableIndexType(field, index));
+        };
+
+        $scope.tableIndexSave = function(field, curIdx, stopEdit) {
+            const indexName = tableIndexName(field, curIdx);
+            const indexType = tableIndexType(field, curIdx);
+
+            const item = $scope.backupItem;
+
+            const indexes = item.indexes;
+
+            if (LegacyUtils.isDefined(indexes)) {
+                const idx = _.findIndex(indexes, function(index) {
+                    return index.name === indexName;
+                });
+
+                // Found duplicate.
+                if (idx >= 0 && idx !== curIdx)
+                    return ErrorPopover.show(LegacyTable.tableFieldId(curIdx, 'IndexName'), 'Index with such name already exists!', $scope.ui, 'query');
+            }
+
+            LegacyTable.tableReset();
+
+            if (curIdx < 0) {
+                const newIndex = {name: indexName, indexType};
+
+                if (item.indexes)
+                    item.indexes.push(newIndex);
+                else
+                    item.indexes = [newIndex];
+            }
+            else {
+                item.indexes[curIdx].name = indexName;
+                item.indexes[curIdx].indexType = indexType;
+            }
+
+            if (!stopEdit) {
+                if (curIdx < 0)
+                    $scope.tableIndexNewItem(field, item.indexes.length - 1);
+                else {
+                    const index = item.indexes[curIdx];
+
+                    if (index.fields && index.fields.length > 0)
+                        $scope.tableIndexItemStartEdit(field, curIdx, 0);
+                    else
+                        $scope.tableIndexNewItem(field, curIdx);
+                }
+            }
+
+            return true;
+        };
+
+        $scope.tableIndexNewItem = function(field, indexIdx) {
+            if ($scope.tableReset(true)) {
+                const index = $scope.backupItem.indexes[indexIdx];
+
+                LegacyTable.tableState(field, -1, 'table-index-fields');
+                LegacyTable.tableFocusInvalidField(-1, 'FieldName' + (index.indexType === 'SORTED' ? 'S' : '') + indexIdx);
+
+                field.newFieldName = null;
+                field.newDirection = true;
+                field.indexIdx = indexIdx;
+            }
+        };
+
+        $scope.tableIndexNewItemActive = function(field, itemIndex) {
+            const indexes = $scope.backupItem.indexes;
+
+            if (indexes) {
+                const index = indexes[itemIndex];
+
+                if (index)
+                    return LegacyTable.tableNewItemActive({model: 'table-index-fields'}) && field.indexIdx === itemIndex;
+            }
+
+            return false;
+        };
+
+        $scope.tableIndexItemEditing = function(field, itemIndex, curIdx) {
+            const indexes = $scope.backupItem.indexes;
+
+            if (indexes) {
+                const index = indexes[itemIndex];
+
+                if (index)
+                    return LegacyTable.tableEditing({model: 'table-index-fields'}, curIdx) && field.indexIdx === itemIndex;
+            }
+
+            return false;
+        };
+
+        function tableIndexItemValue(field, index) {
+            return index < 0 ? {
+                name: field.newFieldName,
+                direction: field.newDirection
+            } : {
+                name: field.curFieldName,
+                direction: field.curDirection
+            };
+        }
+
+        $scope.tableIndexItemStartEdit = function(field, indexIdx, curIdx) {
+            if ($scope.tableReset(true)) {
+                const index = $scope.backupItem.indexes[indexIdx];
+
+                LegacyTable.tableState(field, curIdx, 'table-index-fields');
+
+                const indexItem = index.fields[curIdx];
+
+                field.curFieldName = indexItem.name;
+                field.curDirection = indexItem.direction;
+                field.indexIdx = indexIdx;
+
+                Focus.move('curFieldName' + (index.indexType === 'SORTED' ? 'S' : '') + field.indexIdx + '-' + curIdx);
+            }
+        };
+
+        $scope.tableIndexItemSaveVisible = function(field, index) {
+            return !LegacyUtils.isEmptyString(tableIndexItemValue(field, index).name);
+        };
+
+        $scope.tableIndexItemSave = function(field, indexIdx, curIdx, stopEdit) {
+            const indexItemValue = tableIndexItemValue(field, curIdx);
+
+            const index = $scope.backupItem.indexes[indexIdx];
+
+            const fields = index.fields;
+
+            if (LegacyUtils.isDefined(fields)) {
+                const idx = _.findIndex(fields, (fld) => fld.name === indexItemValue.name);
+
+                // Found duplicate.
+                if (idx >= 0 && idx !== curIdx)
+                    return ErrorPopover.show(LegacyTable.tableFieldId(curIdx, 'FieldName' + (index.indexType === 'SORTED' ? 'S' : '') + indexIdx + (curIdx >= 0 ? '-' : '')), 'Field with such name already exists in index!', $scope.ui, 'query');
+            }
+
+            LegacyTable.tableReset();
+
+            field.indexIdx = -1;
+
+            if (curIdx < 0) {
+                if (index.fields)
+                    index.fields.push(indexItemValue);
+                else
+                    index.fields = [indexItemValue];
+
+                if (!stopEdit)
+                    $scope.tableIndexNewItem(field, indexIdx);
+            }
+            else {
+                index.fields[curIdx] = indexItemValue;
+
+                if (!stopEdit) {
+                    if (curIdx < index.fields.length - 1)
+                        $scope.tableIndexItemStartEdit(field, indexIdx, curIdx + 1);
+                    else
+                        $scope.tableIndexNewItem(field, indexIdx);
+                }
+            }
+
+            return true;
+        };
+
+        $scope.tableRemoveIndexItem = function(index, curIdx) {
+            LegacyTable.tableReset();
+
+            index.fields.splice(curIdx, 1);
+        };
+
+        $scope.resetAll = function() {
+            LegacyTable.tableReset();
+
+            Confirm.confirm('Are you sure you want to undo all changes for current domain model?')
+                .then(function() {
+                    $scope.backupItem = $scope.selectedItem ? angular.copy($scope.selectedItem) : prepareNewItem();
+                    $scope.ui.inputForm.$error = {};
+                    $scope.ui.inputForm.$setPristine();
+                });
+        };
+    }
+]];

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/frontend/controllers/igfs-controller.js
----------------------------------------------------------------------
diff --git a/modules/web-console/frontend/controllers/igfs-controller.js b/modules/web-console/frontend/controllers/igfs-controller.js
new file mode 100644
index 0000000..7617712
--- /dev/null
+++ b/modules/web-console/frontend/controllers/igfs-controller.js
@@ -0,0 +1,416 @@
+/*
+ * 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.
+ */
+
+// Controller for IGFS screen.
+export default ['igfsController', [
+    '$scope', '$http', '$state', '$filter', '$timeout', 'IgniteLegacyUtils', 'IgniteMessages', 'IgniteConfirm', 'IgniteClone', 'IgniteLoading', 'IgniteModelNormalizer', 'IgniteUnsavedChangesGuard', 'IgniteLegacyTable', 'igniteConfigurationResource', 'IgniteErrorPopover', 'IgniteFormUtils',
+    function($scope, $http, $state, $filter, $timeout, LegacyUtils, Messages, Confirm, Clone, Loading, ModelNormalizer, UnsavedChangesGuard, LegacyTable, Resource, ErrorPopover, FormUtils) {
+        UnsavedChangesGuard.install($scope);
+
+        const emptyIgfs = {empty: true};
+
+        let __original_value;
+
+        const blank = {
+            ipcEndpointConfiguration: {},
+            secondaryFileSystem: {}
+        };
+
+        // We need to initialize backupItem with empty object in order to properly used from angular directives.
+        $scope.backupItem = emptyIgfs;
+
+        $scope.ui = FormUtils.formUI();
+        $scope.ui.activePanels = [0];
+        $scope.ui.topPanels = [0];
+
+        $scope.compactJavaName = FormUtils.compactJavaName;
+        $scope.widthIsSufficient = FormUtils.widthIsSufficient;
+        $scope.saveBtnTipText = FormUtils.saveBtnTipText;
+
+        $scope.tableSave = function(field, index, stopEdit) {
+            if (field.type === 'pathModes' && LegacyTable.tablePairSaveVisible(field, index))
+                return LegacyTable.tablePairSave($scope.tablePairValid, $scope.backupItem, field, index, stopEdit);
+
+            return true;
+        };
+
+        $scope.tableReset = (trySave) => {
+            const field = LegacyTable.tableField();
+
+            if (trySave && LegacyUtils.isDefined(field) && !$scope.tableSave(field, LegacyTable.tableEditedRowIndex(), true))
+                return false;
+
+            LegacyTable.tableReset();
+
+            return true;
+        };
+
+        $scope.tableNewItem = function(field) {
+            if ($scope.tableReset(true))
+                LegacyTable.tableNewItem(field);
+        };
+
+        $scope.tableNewItemActive = LegacyTable.tableNewItemActive;
+
+        $scope.tableStartEdit = function(item, field, index) {
+            if ($scope.tableReset(true))
+                LegacyTable.tableStartEdit(item, field, index, $scope.tableSave);
+        };
+
+        $scope.tableEditing = LegacyTable.tableEditing;
+        $scope.tablePairSave = LegacyTable.tablePairSave;
+        $scope.tablePairSaveVisible = LegacyTable.tablePairSaveVisible;
+
+        $scope.tableRemove = function(item, field, index) {
+            if ($scope.tableReset(true))
+                LegacyTable.tableRemove(item, field, index);
+        };
+
+        $scope.tablePairValid = function(item, field, index, stopEdit) {
+            const pairValue = LegacyTable.tablePairValue(field, index);
+
+            const model = item[field.model];
+
+            if (LegacyUtils.isDefined(model)) {
+                const idx = _.findIndex(model, function(pair) {
+                    return pair.path === pairValue.key;
+                });
+
+                // Found duplicate.
+                if (idx >= 0 && idx !== index) {
+                    if (stopEdit)
+                        return false;
+
+                    return ErrorPopover.show(LegacyTable.tableFieldId(index, 'KeyPathMode'), 'Such path already exists!', $scope.ui, 'misc');
+                }
+            }
+
+            return true;
+        };
+
+        $scope.tblPathModes = {
+            type: 'pathModes',
+            model: 'pathModes',
+            focusId: 'PathMode',
+            ui: 'table-pair',
+            keyName: 'path',
+            valueName: 'mode',
+            save: $scope.tableSave
+        };
+
+        $scope.igfsModes = LegacyUtils.mkOptions(['PRIMARY', 'PROXY', 'DUAL_SYNC', 'DUAL_ASYNC']);
+
+        $scope.contentVisible = function() {
+            const item = $scope.backupItem;
+
+            return !item.empty && (!item._id || _.find($scope.displayedRows, {_id: item._id}));
+        };
+
+        $scope.toggleExpanded = function() {
+            $scope.ui.expanded = !$scope.ui.expanded;
+
+            ErrorPopover.hide();
+        };
+
+        $scope.igfss = [];
+        $scope.clusters = [];
+
+        function selectFirstItem() {
+            if ($scope.igfss.length > 0)
+                $scope.selectItem($scope.igfss[0]);
+        }
+
+        Loading.start('loadingIgfsScreen');
+
+        // When landing on the page, get IGFSs and show them.
+        Resource.read()
+            .then(({spaces, clusters, igfss}) => {
+                $scope.spaces = spaces;
+
+                $scope.igfss = igfss || [];
+
+                // For backward compatibility set colocateMetadata and relaxedConsistency default values.
+                _.forEach($scope.igfss, (igfs) => {
+                    if (_.isUndefined(igfs.colocateMetadata))
+                        igfs.colocateMetadata = true;
+
+                    if (_.isUndefined(igfs.relaxedConsistency))
+                        igfs.relaxedConsistency = true;
+                });
+
+                $scope.clusters = _.map(clusters || [], (cluster) => ({
+                    label: cluster.name,
+                    value: cluster._id
+                }));
+
+                if ($state.params.linkId)
+                    $scope.createItem($state.params.linkId);
+                else {
+                    const lastSelectedIgfs = angular.fromJson(sessionStorage.lastSelectedIgfs);
+
+                    if (lastSelectedIgfs) {
+                        const idx = _.findIndex($scope.igfss, function(igfs) {
+                            return igfs._id === lastSelectedIgfs;
+                        });
+
+                        if (idx >= 0)
+                            $scope.selectItem($scope.igfss[idx]);
+                        else {
+                            sessionStorage.removeItem('lastSelectedIgfs');
+
+                            selectFirstItem();
+                        }
+                    }
+                    else
+                        selectFirstItem();
+                }
+
+                $scope.$watch('ui.inputForm.$valid', function(valid) {
+                    if (valid && ModelNormalizer.isEqual(__original_value, $scope.backupItem))
+                        $scope.ui.inputForm.$dirty = false;
+                });
+
+                $scope.$watch('backupItem', function(val) {
+                    if (!$scope.ui.inputForm)
+                        return;
+
+                    const form = $scope.ui.inputForm;
+
+                    if (form.$valid && ModelNormalizer.isEqual(__original_value, val))
+                        form.$setPristine();
+                    else
+                        form.$setDirty();
+                }, true);
+
+                $scope.$watch('ui.activePanels.length', () => {
+                    ErrorPopover.hide();
+                });
+            })
+            .catch(Messages.showError)
+            .then(() => {
+                $scope.ui.ready = true;
+                $scope.ui.inputForm && $scope.ui.inputForm.$setPristine();
+
+                Loading.finish('loadingIgfsScreen');
+            });
+
+        $scope.selectItem = function(item, backup) {
+            function selectItem() {
+                LegacyTable.tableReset();
+
+                $scope.selectedItem = item;
+
+                try {
+                    if (item && item._id)
+                        sessionStorage.lastSelectedIgfs = angular.toJson(item._id);
+                    else
+                        sessionStorage.removeItem('lastSelectedIgfs');
+                }
+                catch (ignored) {
+                    // No-op.
+                }
+
+                if (backup)
+                    $scope.backupItem = backup;
+                else if (item)
+                    $scope.backupItem = angular.copy(item);
+                else
+                    $scope.backupItem = emptyIgfs;
+
+                $scope.backupItem = angular.merge({}, blank, $scope.backupItem);
+
+                if ($scope.ui.inputForm) {
+                    $scope.ui.inputForm.$error = {};
+                    $scope.ui.inputForm.$setPristine();
+                }
+
+                __original_value = ModelNormalizer.normalize($scope.backupItem);
+
+                if (LegacyUtils.getQueryVariable('new'))
+                    $state.go('base.configuration.igfs');
+            }
+
+            FormUtils.confirmUnsavedChanges($scope.backupItem && $scope.ui.inputForm && $scope.ui.inputForm.$dirty, selectItem);
+        };
+
+        $scope.linkId = () => $scope.backupItem._id ? $scope.backupItem._id : 'create';
+
+        function prepareNewItem(linkId) {
+            return {
+                space: $scope.spaces[0]._id,
+                ipcEndpointEnabled: true,
+                fragmentizerEnabled: true,
+                colocateMetadata: true,
+                relaxedConsistency: true,
+                clusters: linkId && _.find($scope.clusters, {value: linkId}) ? [linkId] :
+                    (_.isEmpty($scope.clusters) ? [] : [$scope.clusters[0].value])
+            };
+        }
+
+        // Add new IGFS.
+        $scope.createItem = function(linkId) {
+            if ($scope.tableReset(true)) {
+                $timeout(() => FormUtils.ensureActivePanel($scope.ui, 'general', 'igfsNameInput'));
+
+                $scope.selectItem(null, prepareNewItem(linkId));
+            }
+        };
+
+        // Check IGFS logical consistency.
+        function validate(item) {
+            ErrorPopover.hide();
+
+            if (LegacyUtils.isEmptyString(item.name))
+                return ErrorPopover.show('igfsNameInput', 'IGFS name should not be empty!', $scope.ui, 'general');
+
+            if (!LegacyUtils.checkFieldValidators($scope.ui))
+                return false;
+
+            if (!item.secondaryFileSystemEnabled && (item.defaultMode === 'PROXY'))
+                return ErrorPopover.show('secondaryFileSystem-title', 'Secondary file system should be configured for "PROXY" IGFS mode!', $scope.ui, 'secondaryFileSystem');
+
+            if (item.pathModes) {
+                for (let pathIx = 0; pathIx < item.pathModes.length; pathIx++) {
+                    if (!item.secondaryFileSystemEnabled && item.pathModes[pathIx].mode === 'PROXY')
+                        return ErrorPopover.show('secondaryFileSystem-title', 'Secondary file system should be configured for "PROXY" path mode!', $scope.ui, 'secondaryFileSystem');
+                }
+            }
+
+            return true;
+        }
+
+        // Save IGFS in database.
+        function save(item) {
+            $http.post('/api/v1/configuration/igfs/save', item)
+                .success(function(_id) {
+                    $scope.ui.inputForm.$setPristine();
+
+                    const idx = _.findIndex($scope.igfss, function(igfs) {
+                        return igfs._id === _id;
+                    });
+
+                    if (idx >= 0)
+                        angular.merge($scope.igfss[idx], item);
+                    else {
+                        item._id = _id;
+                        $scope.igfss.push(item);
+                    }
+
+                    $scope.selectItem(item);
+
+                    Messages.showInfo('IGFS "' + item.name + '" saved.');
+                })
+                .error(Messages.showError);
+        }
+
+        // Save IGFS.
+        $scope.saveItem = function() {
+            if ($scope.tableReset(true)) {
+                const item = $scope.backupItem;
+
+                if (validate(item))
+                    save(item);
+            }
+        };
+
+        function _igfsNames() {
+            return _.map($scope.igfss, function(igfs) {
+                return igfs.name;
+            });
+        }
+
+        // Clone IGFS with new name.
+        $scope.cloneItem = function() {
+            if ($scope.tableReset(true) && validate($scope.backupItem)) {
+                Clone.confirm($scope.backupItem.name, _igfsNames()).then(function(newName) {
+                    const item = angular.copy($scope.backupItem);
+
+                    delete item._id;
+
+                    item.name = newName;
+
+                    save(item);
+                });
+            }
+        };
+
+        // Remove IGFS from db.
+        $scope.removeItem = function() {
+            LegacyTable.tableReset();
+
+            const selectedItem = $scope.selectedItem;
+
+            Confirm.confirm('Are you sure you want to remove IGFS: "' + selectedItem.name + '"?')
+                .then(function() {
+                    const _id = selectedItem._id;
+
+                    $http.post('/api/v1/configuration/igfs/remove', {_id})
+                        .success(function() {
+                            Messages.showInfo('IGFS has been removed: ' + selectedItem.name);
+
+                            const igfss = $scope.igfss;
+
+                            const idx = _.findIndex(igfss, function(igfs) {
+                                return igfs._id === _id;
+                            });
+
+                            if (idx >= 0) {
+                                igfss.splice(idx, 1);
+
+                                $scope.ui.inputForm.$setPristine();
+
+                                if (igfss.length > 0)
+                                    $scope.selectItem(igfss[0]);
+                                else
+                                    $scope.backupItem = emptyIgfs;
+                            }
+                        })
+                        .error(Messages.showError);
+                });
+        };
+
+        // Remove all IGFS from db.
+        $scope.removeAllItems = function() {
+            LegacyTable.tableReset();
+
+            Confirm.confirm('Are you sure you want to remove all IGFS?')
+                .then(function() {
+                    $http.post('/api/v1/configuration/igfs/remove/all')
+                        .success(function() {
+                            Messages.showInfo('All IGFS have been removed');
+
+                            $scope.igfss = [];
+                            $scope.backupItem = emptyIgfs;
+                            $scope.ui.inputForm.$error = {};
+                            $scope.ui.inputForm.$setPristine();
+                        })
+                        .error(Messages.showError);
+                });
+        };
+
+        $scope.resetAll = function() {
+            LegacyTable.tableReset();
+
+            Confirm.confirm('Are you sure you want to undo all changes for current IGFS?')
+                .then(function() {
+                    $scope.backupItem = $scope.selectedItem ? angular.copy($scope.selectedItem) : prepareNewItem();
+                    $scope.ui.inputForm.$error = {};
+                    $scope.ui.inputForm.$setPristine();
+                });
+        };
+    }
+]];


[20/52] ignite git commit: Web Console beta-3.

Posted by ak...@apache.org.
http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/src/main/js/app/modules/ace.module.js
----------------------------------------------------------------------
diff --git a/modules/web-console/src/main/js/app/modules/ace.module.js b/modules/web-console/src/main/js/app/modules/ace.module.js
deleted file mode 100644
index 4920a6f..0000000
--- a/modules/web-console/src/main/js/app/modules/ace.module.js
+++ /dev/null
@@ -1,269 +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 angular from 'angular';
-
-angular
-    .module('ignite-console.ace', [])
-    .constant('igniteAceConfig', {})
-    .directive('igniteAce', ['igniteAceConfig', (aceConfig) => {
-        if (angular.isUndefined(window.ace))
-            throw new Error('ignite-ace need ace to work... (o rly?)');
-
-        /**
-         * Sets editor options such as the wrapping mode or the syntax checker.
-         *
-         * The supported options are:
-         *
-         *   <ul>
-         *     <li>showGutter</li>
-         *     <li>useWrapMode</li>
-         *     <li>onLoad</li>
-         *     <li>theme</li>
-         *     <li>mode</li>
-         *   </ul>
-         *
-         * @param acee
-         * @param session ACE editor session.
-         * @param {object} opts Options to be set.
-         */
-        const setOptions = (acee, session, opts) => {
-            // Sets the ace worker path, if running from concatenated or minified source.
-            if (angular.isDefined(opts.workerPath)) {
-                const config = window.ace.acequire('ace/config');
-
-                config.set('workerPath', opts.workerPath);
-            }
-
-            // Ace requires loading.
-            _.forEach(opts.require, (n) => window.ace.acequire(n));
-
-            // Boolean options.
-            if (angular.isDefined(opts.showGutter))
-                acee.renderer.setShowGutter(opts.showGutter);
-
-            if (angular.isDefined(opts.useWrapMode))
-                session.setUseWrapMode(opts.useWrapMode);
-
-            if (angular.isDefined(opts.showInvisibles))
-                acee.renderer.setShowInvisibles(opts.showInvisibles);
-
-            if (angular.isDefined(opts.showIndentGuides))
-                acee.renderer.setDisplayIndentGuides(opts.showIndentGuides);
-
-            if (angular.isDefined(opts.useSoftTabs))
-                session.setUseSoftTabs(opts.useSoftTabs);
-
-            if (angular.isDefined(opts.showPrintMargin))
-                acee.setShowPrintMargin(opts.showPrintMargin);
-
-            // Commands.
-            if (angular.isDefined(opts.disableSearch) && opts.disableSearch) {
-                acee.commands.addCommands([{
-                    name: 'unfind',
-                    bindKey: {
-                        win: 'Ctrl-F',
-                        mac: 'Command-F'
-                    },
-                    exec: _.constant(false),
-                    readOnly: true
-                }]);
-            }
-
-            // Base options.
-            if (angular.isString(opts.theme))
-                acee.setTheme('ace/theme/' + opts.theme);
-
-            if (angular.isString(opts.mode))
-                session.setMode('ace/mode/' + opts.mode);
-
-            if (angular.isDefined(opts.firstLineNumber)) {
-                if (angular.isNumber(opts.firstLineNumber))
-                    session.setOption('firstLineNumber', opts.firstLineNumber);
-                else if (angular.isFunction(opts.firstLineNumber))
-                    session.setOption('firstLineNumber', opts.firstLineNumber());
-            }
-
-            // Advanced options.
-            if (angular.isDefined(opts.advanced)) {
-                for (const key in opts.advanced) {
-                    if (opts.advanced.hasOwnProperty(key)) {
-                        // Create a javascript object with the key and value.
-                        const obj = {name: key, value: opts.advanced[key]};
-
-                        // Try to assign the option to the ace editor.
-                        acee.setOption(obj.name, obj.value);
-                    }
-                }
-            }
-
-            // Advanced options for the renderer.
-            if (angular.isDefined(opts.rendererOptions)) {
-                for (const key in opts.rendererOptions) {
-                    if (opts.rendererOptions.hasOwnProperty(key)) {
-                        // Create a javascript object with the key and value.
-                        const obj = {name: key, value: opts.rendererOptions[key]};
-
-                        // Try to assign the option to the ace editor.
-                        acee.renderer.setOption(obj.name, obj.value);
-                    }
-                }
-            }
-
-            // onLoad callbacks.
-            _.forEach(opts.callbacks, (cb) => {
-                if (angular.isFunction(cb))
-                    cb(acee);
-            });
-        };
-
-        return {
-            restrict: 'EA',
-            require: ['?ngModel', '?^form'],
-            link: (scope, elm, attrs, [ngModel, form]) => {
-                /**
-                 * Corresponds the igniteAceConfig ACE configuration.
-                 *
-                 * @type object
-                 */
-                const options = aceConfig.ace || {};
-
-                /**
-                 * IgniteAceConfig merged with user options via json in attribute or data binding.
-                 *
-                 * @type object
-                 */
-                let opts = angular.extend({}, options, scope.$eval(attrs.igniteAce));
-
-                /**
-                 * ACE editor.
-                 *
-                 * @type object
-                 */
-                const acee = window.ace.edit(elm[0]);
-
-                /**
-                 * ACE editor session.
-                 *
-                 * @type object
-                 * @see [EditSession]{@link http://ace.c9.io/#nav=api&api=edit_session}
-                 */
-                const session = acee.getSession();
-
-                /**
-                 * Reference to a change listener created by the listener factory.
-                 *
-                 * @function
-                 * @see listenerFactory.onChange
-                 */
-                let onChangeListener;
-
-                /**
-                 * Creates a change listener which propagates the change event and the editor session
-                 * to the callback from the user option onChange.
-                 * It might be exchanged during runtime, if this happens the old listener will be unbound.
-                 *
-                 * @param callback Callback function defined in the user options.
-                 * @see onChangeListener
-                 */
-                const onChangeFactory = (callback) => {
-                    return (e) => {
-                        const newValue = session.getValue();
-
-                        if (ngModel && newValue !== ngModel.$viewValue &&
-                                // HACK make sure to only trigger the apply outside of the
-                                // digest loop 'cause ACE is actually using this callback
-                                // for any text transformation !
-                            !scope.$$phase && !scope.$root.$$phase)
-                            scope.$eval(() => ngModel.$setViewValue(newValue));
-
-                        if (angular.isDefined(callback)) {
-                            scope.$evalAsync(() => {
-                                if (angular.isFunction(callback))
-                                    callback([e, acee]);
-                                else
-                                    throw new Error('ignite-ace use a function as callback');
-                            });
-                        }
-                    };
-                };
-
-                attrs.$observe('readonly', (value) => acee.setReadOnly(!!value || value === ''));
-
-                // Value Blind.
-                if (ngModel) {
-                    // Remove "ngModel" controller from parent form for correct dirty checks.
-                    form && form.$removeControl(ngModel);
-
-                    ngModel.$formatters.push((value) => {
-                        if (angular.isUndefined(value) || value === null)
-                            return '';
-
-                        if (angular.isObject(value) || angular.isArray(value))
-                            throw new Error('ignite-ace cannot use an object or an array as a model');
-
-                        return value;
-                    });
-
-                    ngModel.$render = () => session.setValue(ngModel.$viewValue);
-
-                    acee.on('change', () => ngModel.$setViewValue(acee.getValue()));
-                }
-
-                // Listen for option updates.
-                const updateOptions = (current, previous) => {
-                    if (current === previous)
-                        return;
-
-                    opts = angular.extend({}, options, scope.$eval(attrs.igniteAce));
-
-                    opts.callbacks = [opts.onLoad];
-
-                    // Also call the global onLoad handler.
-                    if (opts.onLoad !== options.onLoad)
-                        opts.callbacks.unshift(options.onLoad);
-
-                    // Unbind old change listener.
-                    session.removeListener('change', onChangeListener);
-
-                    // Bind new change listener.
-                    onChangeListener = onChangeFactory(opts.onChange);
-
-                    session.on('change', onChangeListener);
-
-                    setOptions(acee, session, opts);
-                };
-
-                scope.$watch(attrs.igniteAce, updateOptions, /* deep watch */ true);
-
-                // Set the options here, even if we try to watch later,
-                // if this line is missing things go wrong (and the tests will also fail).
-                updateOptions(options);
-
-                elm.on('$destroy', () => {
-                    acee.session.$stopWorker();
-                    acee.destroy();
-                });
-
-                scope.$watch(() => [elm[0].offsetWidth, elm[0].offsetHeight],
-                    () => {
-                        acee.resize();
-                        acee.renderer.updateFull();
-                    }, true);
-            }
-        };
-    }]);

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/src/main/js/app/modules/agent/agent.module.js
----------------------------------------------------------------------
diff --git a/modules/web-console/src/main/js/app/modules/agent/agent.module.js b/modules/web-console/src/main/js/app/modules/agent/agent.module.js
deleted file mode 100644
index ca95166..0000000
--- a/modules/web-console/src/main/js/app/modules/agent/agent.module.js
+++ /dev/null
@@ -1,323 +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 angular from 'angular';
-import io from 'socket.io-client'; // eslint-disable-line no-unused-vars
-
-class IgniteAgentMonitor {
-    constructor(socketFactory, $root, $q, $state, $modal, Messages) {
-        this._scope = $root.$new();
-
-        $root.$watch('user', () => {
-            this._scope.user = $root.user;
-        });
-
-        $root.$on('$stateChangeStart', () => {
-            this.stopWatch();
-        });
-
-        // Pre-fetch modal dialogs.
-        this._downloadAgentModal = $modal({
-            scope: this._scope,
-            templateUrl: '/templates/agent-download.html',
-            show: false,
-            backdrop: 'static',
-            keyboard: false
-        });
-
-        const _modalHide = this._downloadAgentModal.hide;
-
-        /**
-         * Special dialog hide function.
-         */
-        this._downloadAgentModal.hide = () => {
-            Messages.hideAlert();
-
-            _modalHide();
-        };
-
-        /**
-         * Close dialog and go by specified link.
-         */
-        this._scope.back = () => {
-            this.stopWatch();
-
-            if (this._scope.backState)
-                this._scope.$$postDigest(() => $state.go(this._scope.backState));
-        };
-
-        this._scope.downloadAgent = () => {
-            const lnk = document.createElement('a');
-
-            lnk.setAttribute('href', '/api/v1/agent/download/zip');
-            lnk.setAttribute('target', '_self');
-            lnk.setAttribute('download', null);
-            lnk.style.display = 'none';
-
-            document.body.appendChild(lnk);
-
-            lnk.click();
-
-            document.body.removeChild(lnk);
-        };
-
-        this._scope.hasAgents = null;
-        this._scope.showModal = false;
-
-        /**
-         * @type {Socket}
-         */
-        this._socket = null;
-
-        this._socketFactory = socketFactory;
-
-        this._$q = $q;
-
-        this.Messages = Messages;
-    }
-
-    /**
-     * @private
-     */
-    checkModal() {
-        if (this._scope.showModal && !this._scope.hasAgents)
-            this._downloadAgentModal.$promise.then(this._downloadAgentModal.show);
-        else if ((this._scope.hasAgents || !this._scope.showModal) && this._downloadAgentModal.$isShown)
-            this._downloadAgentModal.hide();
-    }
-
-    /**
-     * @returns {Promise}
-     */
-    awaitAgent() {
-        if (this._scope.hasAgents)
-            return this._$q.when();
-
-        const latch = this._$q.defer();
-
-        const offConnected = this._scope.$on('agent:watch', (event, state) => {
-            if (state !== 'DISCONNECTED')
-                offConnected();
-
-            if (state === 'CONNECTED')
-                return latch.resolve();
-
-            if (state === 'STOPPED')
-                return latch.reject('Agent watch stopped.');
-        });
-
-        return latch.promise;
-    }
-
-    init() {
-        this._socket = this._socketFactory();
-
-        const disconnectFn = () => {
-            this._scope.hasAgents = false;
-
-            this.checkModal();
-
-            this._scope.$broadcast('agent:watch', 'DISCONNECTED');
-        };
-
-        this._socket.on('connect_error', disconnectFn);
-        this._socket.on('disconnect', disconnectFn);
-
-        this._socket.on('agent:count', ({count}) => {
-            this._scope.hasAgents = count > 0;
-
-            this.checkModal();
-
-            this._scope.$broadcast('agent:watch', this._scope.hasAgents ? 'CONNECTED' : 'DISCONNECTED');
-        });
-    }
-
-    /**
-     * @param {Object} back
-     * @returns {Promise}
-     */
-    startWatch(back) {
-        this._scope.backState = back.state;
-        this._scope.backText = back.text;
-
-        this._scope.agentGoal = back.goal;
-
-        if (back.onDisconnect) {
-            this._scope.offDisconnect = this._scope.$on('agent:watch', (e, state) =>
-                state === 'DISCONNECTED' && back.onDisconnect());
-        }
-
-        this._scope.showModal = true;
-
-        // Remove blinking on init.
-        if (this._scope.hasAgents !== null)
-            this.checkModal();
-
-        return this.awaitAgent();
-    }
-
-    /**
-     *
-     * @param {String} event
-     * @param {Object} [args]
-     * @returns {Promise}
-     * @private
-     */
-    _emit(event, ...args) {
-        if (!this._socket)
-            return this._$q.reject('Failed to connect to server');
-
-        const latch = this._$q.defer();
-
-        const onDisconnect = () => {
-            this._socket.removeListener('disconnect', onDisconnect);
-
-            latch.reject('Connection to server was closed');
-        };
-
-        this._socket.on('disconnect', onDisconnect);
-
-        args.push((err, res) => {
-            this._socket.removeListener('disconnect', onDisconnect);
-
-            if (err)
-                latch.reject(err);
-
-            latch.resolve(res);
-        });
-
-        this._socket.emit(event, ...args);
-
-        return latch.promise;
-    }
-
-    drivers() {
-        return this._emit('schemaImport:drivers');
-    }
-
-    /**
-     *
-     * @param {Object} preset
-     * @returns {Promise}
-     */
-    schemas(preset) {
-        return this._emit('schemaImport:schemas', preset);
-    }
-
-    /**
-     *
-     * @param {Object} preset
-     * @returns {Promise}
-     */
-    tables(preset) {
-        return this._emit('schemaImport:tables', preset);
-    }
-
-    /**
-     * @param {Object} err
-     */
-    showNodeError(err) {
-        if (this._scope.showModal) {
-            this._downloadAgentModal.$promise.then(this._downloadAgentModal.show);
-
-            this.Messages.showError(err);
-        }
-    }
-
-    /**
-     *
-     * @param {String} event
-     * @param {Object} [args]
-     * @returns {Promise}
-     * @private
-     */
-    _rest(event, ...args) {
-        return this._downloadAgentModal.$promise
-            .then(() => this._emit(event, ...args));
-    }
-
-    /**
-     * @param {Boolean} [attr]
-     * @param {Boolean} [mtr]
-     * @returns {Promise}
-     */
-    topology(attr, mtr) {
-        return this._rest('node:topology', !!attr, !!mtr);
-    }
-
-    /**
-     * @param {int} [queryId]
-     * @returns {Promise}
-     */
-    queryClose(queryId) {
-        return this._rest('node:query:close', queryId);
-    }
-
-    /**
-     * @param {String} cacheName Cache name.
-     * @param {int} pageSize
-     * @param {String} [query] Query if null then scan query.
-     * @returns {Promise}
-     */
-    query(cacheName, pageSize, query) {
-        return this._rest('node:query', _.isEmpty(cacheName) ? null : cacheName, pageSize, query);
-    }
-
-    /**
-     * @param {String} cacheName Cache name.
-     * @param {String} [query] Query if null then scan query.
-     * @returns {Promise}
-     */
-    queryGetAll(cacheName, query) {
-        return this._rest('node:query:getAll', _.isEmpty(cacheName) ? null : cacheName, query);
-    }
-
-    /**
-     * @param {String} [cacheName] Cache name.
-     * @returns {Promise}
-     */
-    metadata(cacheName) {
-        return this._rest('node:cache:metadata', _.isEmpty(cacheName) ? null : cacheName);
-    }
-
-    /**
-     * @param {int} queryId
-     * @param {int} pageSize
-     * @returns {Promise}
-     */
-    next(queryId, pageSize) {
-        return this._rest('node:query:fetch', queryId, pageSize);
-    }
-
-    stopWatch() {
-        this._scope.showModal = false;
-
-        this.checkModal();
-
-        this._scope.offDisconnect && this._scope.offDisconnect();
-
-        this._scope.$broadcast('agent:watch', 'STOPPED');
-    }
-}
-
-IgniteAgentMonitor.$inject = ['igniteSocketFactory', '$rootScope', '$q', '$state', '$modal', 'IgniteMessages'];
-
-angular
-    .module('ignite-console.agent', [
-
-    ])
-    .service('IgniteAgentMonitor', IgniteAgentMonitor);

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/src/main/js/app/modules/branding/branding.module.js
----------------------------------------------------------------------
diff --git a/modules/web-console/src/main/js/app/modules/branding/branding.module.js b/modules/web-console/src/main/js/app/modules/branding/branding.module.js
deleted file mode 100644
index cae7c91..0000000
--- a/modules/web-console/src/main/js/app/modules/branding/branding.module.js
+++ /dev/null
@@ -1,45 +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 angular from 'angular';
-
-import IgniteBranding from './branding.provider';
-
-import igniteHeaderLogo from './header-logo.directive';
-import igniteHeaderTitle from './header-title.directive';
-import igniteTerms from './terms.directive';
-import igniteFeatures from './features.directive';
-import igniteFooter from './footer.directive';
-import ignitePoweredByApache from './powered-by-apache.directive';
-
-angular
-.module('ignite-console.branding', [
-    'ui.router.metatags'
-])
-.provider(...IgniteBranding)
-.config(['UIRouterMetatagsProvider', (UIRouterMetatagsProvider) => {
-    UIRouterMetatagsProvider
-        .setDefaultTitle('Apache Ignite - Management Tool and Configuration Wizard')
-        .setTitleSuffix(' \u2013 Apache Ignite Web Console')
-        .setDefaultDescription('The Apache Ignite Web Console is an interactive management tool and configuration wizard which walks you through the creation of config files. Try it now.');
-}])
-.directive(...ignitePoweredByApache)
-.directive(...igniteHeaderLogo)
-.directive(...igniteHeaderTitle)
-.directive(...igniteTerms)
-.directive(...igniteFeatures)
-.directive(...igniteFooter);

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/src/main/js/app/modules/branding/branding.provider.js
----------------------------------------------------------------------
diff --git a/modules/web-console/src/main/js/app/modules/branding/branding.provider.js b/modules/web-console/src/main/js/app/modules/branding/branding.provider.js
deleted file mode 100644
index ce14b34..0000000
--- a/modules/web-console/src/main/js/app/modules/branding/branding.provider.js
+++ /dev/null
@@ -1,111 +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 ['IgniteBranding', [function() {
-    let titleSuffix = ' \u2013 Apache Ignite Web Console';
-
-    let headerLogo = '/images/ignite-logo.png';
-
-    let headerText = 'Management console for Apache Ignite';
-
-    let showIgniteLogo = false;
-
-    let footerHtml = [
-        '<p>Apache Ignite Web Console</p>',
-        '<p>� 2016 The Apache Software Foundation.</p>',
-        '<p>Apache, Apache Ignite, the Apache feather and the Apache Ignite logo are trademarks of The Apache Software Foundation.</p>'
-    ];
-
-    let termsState;
-
-    let featuresHtml = [
-        '<p>Web Console is an interactive management tool which allows to:</p>',
-        '<ul>',
-        '   <li>Create and download cluster configurations</li>',
-        '   <li>Automatically import domain model from any RDBMS</li>',
-        '   <li>Connect to cluster and run SQL analytics on it</li>',
-        '</ul>'
-    ];
-
-    /**
-     * Change title suffix.
-     *
-     * @param {String} suffix.
-     */
-    this.titleSuffix = (suffix) => {
-        titleSuffix = suffix;
-    };
-
-    /**
-     * Change logo in header.
-     *
-     * @param {String} url Logo path.
-     */
-    this.headerLogo = (url) => {
-        headerLogo = url;
-
-        showIgniteLogo = true;
-    };
-
-    /**
-     * Change text in header.
-     *
-     * @param {String} text Header text.
-     */
-    this.headerText = (text) => {
-        headerText = text;
-    };
-
-    /**
-     * Change text in features.
-     *
-     * @param {Array.<String>} rows Features text.
-     */
-    this.featuresHtml = (rows) => {
-        featuresHtml = rows;
-    };
-
-    /**
-     * Change text in footer.
-     *
-     * @param {Array.<String>} rows Footer text.
-     */
-    this.footerHtml = (rows) => {
-        footerHtml = rows;
-    };
-
-    /**
-     * Set terms and conditions stage.
-     *
-     * @param {String} state
-     */
-    this.termsState = (state) => {
-        termsState = state;
-    };
-
-    this.$get = [() => {
-        return {
-            titleSuffix,
-            headerLogo,
-            headerText,
-            featuresHtml: featuresHtml.join('\n'),
-            footerHtml: footerHtml.join('\n'),
-            showIgniteLogo,
-            termsState
-        };
-    }];
-}]];

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/src/main/js/app/modules/branding/features.directive.js
----------------------------------------------------------------------
diff --git a/modules/web-console/src/main/js/app/modules/branding/features.directive.js b/modules/web-console/src/main/js/app/modules/branding/features.directive.js
deleted file mode 100644
index 9226a3f..0000000
--- a/modules/web-console/src/main/js/app/modules/branding/features.directive.js
+++ /dev/null
@@ -1,35 +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.
- */
-
-const template = '<div class="features" ng-bind-html="features.html"></div>';
-
-export default ['igniteFeatures', ['IgniteBranding', (branding) => {
-    function controller() {
-        const ctrl = this;
-
-        ctrl.html = branding.featuresHtml;
-    }
-
-    return {
-        restrict: 'E',
-        template,
-        controller,
-        controllerAs: 'features',
-        replace: true
-    };
-}]];
-

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/src/main/js/app/modules/branding/footer.directive.js
----------------------------------------------------------------------
diff --git a/modules/web-console/src/main/js/app/modules/branding/footer.directive.js b/modules/web-console/src/main/js/app/modules/branding/footer.directive.js
deleted file mode 100644
index f0b1994..0000000
--- a/modules/web-console/src/main/js/app/modules/branding/footer.directive.js
+++ /dev/null
@@ -1,34 +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.
- */
-
-const template = '<div class="footer" ng-bind-html="footer.html"></div>';
-
-export default ['igniteFooter', ['IgniteBranding', (branding) => {
-    function controller() {
-        const ctrl = this;
-
-        ctrl.html = branding.footerHtml;
-    }
-
-    return {
-        restrict: 'E',
-        template,
-        controller,
-        controllerAs: 'footer',
-        replace: true
-    };
-}]];

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/src/main/js/app/modules/branding/header-logo.directive.js
----------------------------------------------------------------------
diff --git a/modules/web-console/src/main/js/app/modules/branding/header-logo.directive.js b/modules/web-console/src/main/js/app/modules/branding/header-logo.directive.js
deleted file mode 100644
index 423de9c..0000000
--- a/modules/web-console/src/main/js/app/modules/branding/header-logo.directive.js
+++ /dev/null
@@ -1,34 +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 templateUrl from './header-logo.jade';
-
-export default ['igniteHeaderLogo', ['IgniteBranding', (branding) => {
-    function controller() {
-        const ctrl = this;
-
-        ctrl.url = branding.headerLogo;
-    }
-
-    return {
-        restrict: 'E',
-        templateUrl,
-        controller,
-        controllerAs: 'logo',
-        replace: true
-    };
-}]];

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/src/main/js/app/modules/branding/header-logo.jade
----------------------------------------------------------------------
diff --git a/modules/web-console/src/main/js/app/modules/branding/header-logo.jade b/modules/web-console/src/main/js/app/modules/branding/header-logo.jade
deleted file mode 100644
index b807921..0000000
--- a/modules/web-console/src/main/js/app/modules/branding/header-logo.jade
+++ /dev/null
@@ -1,18 +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.
-
-a(href='/')
-    img.navbar-brand(ng-src='{{logo.url}}' height='40')

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/src/main/js/app/modules/branding/header-title.directive.js
----------------------------------------------------------------------
diff --git a/modules/web-console/src/main/js/app/modules/branding/header-title.directive.js b/modules/web-console/src/main/js/app/modules/branding/header-title.directive.js
deleted file mode 100644
index d560e0a..0000000
--- a/modules/web-console/src/main/js/app/modules/branding/header-title.directive.js
+++ /dev/null
@@ -1,35 +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.
- */
-
-const template = '<h1 class="title">{{::title.text}}</h1>';
-
-export default ['igniteHeaderTitle', ['IgniteBranding', (branding) => {
-    function controller() {
-        const ctrl = this;
-
-        ctrl.text = branding.headerText;
-    }
-
-    return {
-        restrict: 'E',
-        template,
-        controller,
-        controllerAs: 'title',
-        replace: true
-    };
-}]];
-

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/src/main/js/app/modules/branding/powered-by-apache.directive.js
----------------------------------------------------------------------
diff --git a/modules/web-console/src/main/js/app/modules/branding/powered-by-apache.directive.js b/modules/web-console/src/main/js/app/modules/branding/powered-by-apache.directive.js
deleted file mode 100644
index 2f02446..0000000
--- a/modules/web-console/src/main/js/app/modules/branding/powered-by-apache.directive.js
+++ /dev/null
@@ -1,35 +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 templateUrl from './powered-by-apache.jade';
-
-export default ['ignitePoweredByApache', ['IgniteBranding', (branding) => {
-    function controller() {
-        const ctrl = this;
-
-        ctrl.show = branding.showIgniteLogo;
-    }
-
-    return {
-        restrict: 'E',
-        templateUrl,
-        controller,
-        controllerAs: 'poweredBy',
-        replace: true
-    };
-}]];
-

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/src/main/js/app/modules/branding/powered-by-apache.jade
----------------------------------------------------------------------
diff --git a/modules/web-console/src/main/js/app/modules/branding/powered-by-apache.jade b/modules/web-console/src/main/js/app/modules/branding/powered-by-apache.jade
deleted file mode 100644
index af9aadf..0000000
--- a/modules/web-console/src/main/js/app/modules/branding/powered-by-apache.jade
+++ /dev/null
@@ -1,18 +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.
-
-a(ng-if='poweredBy.show' href='//ignite.apache.org' target='_blank')
-    img(ng-src='/images/pb-ignite.png' height='65')

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/src/main/js/app/modules/branding/terms.directive.js
----------------------------------------------------------------------
diff --git a/modules/web-console/src/main/js/app/modules/branding/terms.directive.js b/modules/web-console/src/main/js/app/modules/branding/terms.directive.js
deleted file mode 100644
index 0207745..0000000
--- a/modules/web-console/src/main/js/app/modules/branding/terms.directive.js
+++ /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.
- */
-
-export default ['igniteTerms', ['IgniteBranding', (branding) => {
-    function controller() {
-        const ctrl = this;
-
-        ctrl.termsState = branding.termsState;
-    }
-
-    return {
-        restrict: 'A',
-        controller,
-        controllerAs: 'terms'
-    };
-}]];

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/src/main/js/app/modules/configuration/EventGroups.provider.js
----------------------------------------------------------------------
diff --git a/modules/web-console/src/main/js/app/modules/configuration/EventGroups.provider.js b/modules/web-console/src/main/js/app/modules/configuration/EventGroups.provider.js
deleted file mode 100644
index 61f3188..0000000
--- a/modules/web-console/src/main/js/app/modules/configuration/EventGroups.provider.js
+++ /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.
- */
-
-// Events groups.
-import GROUPS from 'app/data/event-types.json';
-
-export default ['igniteEventGroups', function() {
-    const groups = GROUPS;
-
-    this.push = (data) => groups.push(data);
-
-    this.$get = [() => {
-        return groups;
-    }];
-}];
-

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/src/main/js/app/modules/configuration/Sidebar.provider.js
----------------------------------------------------------------------
diff --git a/modules/web-console/src/main/js/app/modules/configuration/Sidebar.provider.js b/modules/web-console/src/main/js/app/modules/configuration/Sidebar.provider.js
deleted file mode 100644
index 8bd5ba3..0000000
--- a/modules/web-console/src/main/js/app/modules/configuration/Sidebar.provider.js
+++ /dev/null
@@ -1,39 +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 angular from 'angular';
-
-export default ['igniteSidebar', function() {
-    const items = [
-        { text: 'Clusters', sref: 'base.configuration.clusters' },
-        { text: 'Model', sref: 'base.configuration.domains' },
-        { text: 'Caches', sref: 'base.configuration.caches' },
-        { text: 'IGFS', sref: 'base.configuration.igfs' }
-    ];
-
-    this.push = function(data) {
-        items.push(data);
-    };
-
-    this.$get = [function() {
-        const r = angular.copy(items);
-
-        r.push({ text: 'Summary', sref: 'base.configuration.summary' });
-
-        return r;
-    }];
-}];

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/src/main/js/app/modules/configuration/configuration.module.js
----------------------------------------------------------------------
diff --git a/modules/web-console/src/main/js/app/modules/configuration/configuration.module.js b/modules/web-console/src/main/js/app/modules/configuration/configuration.module.js
deleted file mode 100644
index 99830b0..0000000
--- a/modules/web-console/src/main/js/app/modules/configuration/configuration.module.js
+++ /dev/null
@@ -1,41 +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 angular from 'angular';
-
-import igniteEventGroups from './EventGroups.provider';
-import igniteSidebar from './Sidebar.provider';
-
-import GeneratorXml from './generator/Xml.service';
-import GeneratorJava from './generator/Java.service';
-import GeneratorDocker from './generator/Docker.service';
-import GeneratorPom from './generator/Pom.service';
-
-import igniteSidebarDirective from './sidebar.directive';
-
-// Ignite events groups.
-angular
-.module('ignite-console.configuration', [
-
-])
-.provider(...igniteEventGroups)
-.provider(...igniteSidebar)
-.directive(...igniteSidebarDirective)
-.service(...GeneratorXml)
-.service(...GeneratorJava)
-.service(...GeneratorDocker)
-.service(...GeneratorPom);

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/src/main/js/app/modules/configuration/generator/Docker.service.js
----------------------------------------------------------------------
diff --git a/modules/web-console/src/main/js/app/modules/configuration/generator/Docker.service.js b/modules/web-console/src/main/js/app/modules/configuration/generator/Docker.service.js
deleted file mode 100644
index f9776a2..0000000
--- a/modules/web-console/src/main/js/app/modules/configuration/generator/Docker.service.js
+++ /dev/null
@@ -1,78 +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.
- */
-
-/**
- * Docker file generation entry point.
- */
-class GeneratorDocker {
-    /**
-     * Generate from section.
-     *
-     * @param {Object} cluster Cluster.
-     * @param {String} ver Ignite version.
-     * @returns {String}
-     */
-    from(cluster, ver) {
-        return [
-            '# Start from Apache Ignite image.',
-            `FROM apacheignite/ignite:${ver}`
-        ].join('\n');
-    }
-
-    /**
-     * Generate Docker file for cluster.
-     *
-     * @param {Object} cluster Cluster.
-     * @param {String} ver Ignite version.
-     */
-    generate(cluster, ver) {
-        return [
-            this.from(cluster, ver),
-            '',
-            '# Set config uri for node.',
-            `ENV CONFIG_URI config/${cluster.name}-server.xml`,
-            '',
-            '# Copy ignite-http-rest from optional.',
-            'ENV OPTION_LIBS ignite-rest-http',
-            '',
-            '# Update packages and install maven.',
-            'RUN \\',
-            '   apt-get update &&\\',
-            '   apt-get install -y maven',
-            '',
-            '# Append project to container.',
-            `ADD . ${cluster.name}`,
-            '',
-            '# Build project in container.',
-            `RUN mvn -f ${cluster.name}/pom.xml clean package -DskipTests`,
-            '',
-            '# Copy project jars to node classpath.',
-            `RUN mkdir $IGNITE_HOME/libs/${cluster.name} && \\`,
-            `   find ${cluster.name}/target -name "*.jar" -type f -exec cp {} $IGNITE_HOME/libs/${cluster.name} \\; && \\`,
-            `   cp -r ${cluster.name}/config/* $IGNITE_HOME/config`
-        ].join('\n');
-    }
-
-    ignoreFile() {
-        return [
-            'target',
-            'Dockerfile'
-        ].join('\n');
-    }
-}
-
-export default ['GeneratorDocker', GeneratorDocker];

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/src/main/js/app/modules/configuration/generator/Java.service.js
----------------------------------------------------------------------
diff --git a/modules/web-console/src/main/js/app/modules/configuration/generator/Java.service.js b/modules/web-console/src/main/js/app/modules/configuration/generator/Java.service.js
deleted file mode 100644
index 67e19b9..0000000
--- a/modules/web-console/src/main/js/app/modules/configuration/generator/Java.service.js
+++ /dev/null
@@ -1,21 +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.
- */
-
-// TODO IGNITE-2054: need move $generatorJava to services.
-export default ['GeneratorJava', () => {
-    return $generatorJava;
-}];

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/src/main/js/app/modules/configuration/generator/Pom.service.js
----------------------------------------------------------------------
diff --git a/modules/web-console/src/main/js/app/modules/configuration/generator/Pom.service.js b/modules/web-console/src/main/js/app/modules/configuration/generator/Pom.service.js
deleted file mode 100644
index 674c16e..0000000
--- a/modules/web-console/src/main/js/app/modules/configuration/generator/Pom.service.js
+++ /dev/null
@@ -1,210 +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.
- */
-
-// Java built-in class names.
-import POM_DEPENDENCIES from 'app/data/pom-dependencies.json';
-
-/**
- * Pom file generation entry point.
- */
-class GeneratorPom {
-    escapeId(s) {
-        if (typeof (s) !== 'string')
-            return s;
-
-        return s.replace(/[^A-Za-z0-9_\-.]+/g, '_');
-    }
-
-    addProperty(res, tag, val) {
-        res.line('<' + tag + '>' + val + '</' + tag + '>');
-    }
-
-    addDependency(deps, groupId, artifactId, version, jar) {
-        if (!_.find(deps, (dep) => dep.groupId === groupId && dep.artifactId === artifactId))
-            deps.push({groupId, artifactId, version, jar});
-    }
-
-    addResource(res, dir, exclude) {
-        res.startBlock('<resource>');
-        if (dir)
-            this.addProperty(res, 'directory', dir);
-
-        if (exclude) {
-            res.startBlock('<excludes>');
-            this.addProperty(res, 'exclude', exclude);
-            res.endBlock('</excludes>');
-        }
-
-        res.endBlock('</resource>');
-    }
-
-    artifact(res, cluster, igniteVersion) {
-        this.addProperty(res, 'groupId', 'org.apache.ignite');
-        this.addProperty(res, 'artifactId', this.escapeId(cluster.name) + '-project');
-        this.addProperty(res, 'version', igniteVersion);
-
-        res.needEmptyLine = true;
-    }
-
-    dependencies(res, cluster, deps) {
-        if (!res)
-            res = $generatorCommon.builder();
-
-        res.startBlock('<dependencies>');
-
-        _.forEach(deps, (dep) => {
-            res.startBlock('<dependency>');
-
-            this.addProperty(res, 'groupId', dep.groupId);
-            this.addProperty(res, 'artifactId', dep.artifactId);
-            this.addProperty(res, 'version', dep.version);
-
-            if (dep.jar) {
-                this.addProperty(res, 'scope', 'system');
-                this.addProperty(res, 'systemPath', '${project.basedir}/jdbc-drivers/' + dep.jar);
-            }
-
-            res.endBlock('</dependency>');
-        });
-
-        res.endBlock('</dependencies>');
-
-        return res;
-    }
-
-    build(res, cluster, excludeGroupIds) {
-        res.startBlock('<build>');
-        res.startBlock('<resources>');
-        this.addResource(res, 'src/main/java', '**/*.java');
-        this.addResource(res, 'src/main/resources');
-        res.endBlock('</resources>');
-
-        res.startBlock('<plugins>');
-        res.startBlock('<plugin>');
-        this.addProperty(res, 'artifactId', 'maven-dependency-plugin');
-        res.startBlock('<executions>');
-        res.startBlock('<execution>');
-        this.addProperty(res, 'id', 'copy-libs');
-        this.addProperty(res, 'phase', 'test-compile');
-        res.startBlock('<goals>');
-        this.addProperty(res, 'goal', 'copy-dependencies');
-        res.endBlock('</goals>');
-        res.startBlock('<configuration>');
-        this.addProperty(res, 'excludeGroupIds', excludeGroupIds.join(','));
-        this.addProperty(res, 'outputDirectory', 'target/libs');
-        this.addProperty(res, 'includeScope', 'compile');
-        this.addProperty(res, 'excludeTransitive', 'true');
-        res.endBlock('</configuration>');
-        res.endBlock('</execution>');
-        res.endBlock('</executions>');
-        res.endBlock('</plugin>');
-        res.startBlock('<plugin>');
-        this.addProperty(res, 'artifactId', 'maven-compiler-plugin');
-        this.addProperty(res, 'version', '3.1');
-        res.startBlock('<configuration>');
-        this.addProperty(res, 'source', '1.7');
-        this.addProperty(res, 'target', '1.7');
-        res.endBlock('</configuration>');
-        res.endBlock('</plugin>');
-        res.endBlock('</plugins>');
-        res.endBlock('</build>');
-
-        res.endBlock('</project>');
-    }
-
-    /**
-     * Generate pom.xml.
-     *
-     * @param cluster Cluster  to take info about dependencies.
-     * @param igniteVersion Ignite version for Ignite dependencies.
-     * @param res Resulting output with generated pom.
-     * @returns {string} Generated content.
-     */
-    generate(cluster, igniteVersion, res) {
-        const caches = cluster.caches;
-        const deps = [];
-        const storeDeps = [];
-        const excludeGroupIds = ['org.apache.ignite'];
-
-        const blobStoreFactory = {cacheStoreFactory: {kind: 'CacheHibernateBlobStoreFactory'}};
-
-        if (!res)
-            res = $generatorCommon.builder();
-
-        _.forEach(caches, (cache) => {
-            if (cache.cacheStoreFactory && cache.cacheStoreFactory.kind) {
-                const storeFactory = cache.cacheStoreFactory[cache.cacheStoreFactory.kind];
-
-                if (storeFactory.dialect && (!storeFactory.connectVia || storeFactory.connectVia === 'DataSource')) {
-                    const dep = POM_DEPENDENCIES[storeFactory.dialect];
-
-                    this.addDependency(storeDeps, dep.groupId, dep.artifactId, dep.version, dep.jar);
-                }
-            }
-        });
-
-        res.line('<?xml version="1.0" encoding="UTF-8"?>');
-
-        res.needEmptyLine = true;
-
-        res.line('<!-- ' + $generatorCommon.mainComment() + ' -->');
-
-        res.needEmptyLine = true;
-
-        res.startBlock('<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">');
-
-        res.line('<modelVersion>4.0.0</modelVersion>');
-
-        res.needEmptyLine = true;
-
-        this.artifact(res, cluster, igniteVersion);
-
-        this.addDependency(deps, 'org.apache.ignite', 'ignite-core', igniteVersion);
-
-        this.addDependency(deps, 'org.apache.ignite', 'ignite-spring', igniteVersion);
-        this.addDependency(deps, 'org.apache.ignite', 'ignite-indexing', igniteVersion);
-        this.addDependency(deps, 'org.apache.ignite', 'ignite-rest-http', igniteVersion);
-
-        let dep = POM_DEPENDENCIES[cluster.discovery.kind];
-
-        if (dep)
-            this.addDependency(deps, 'org.apache.ignite', dep.artifactId, igniteVersion);
-
-        if (_.find(cluster.igfss, (igfs) => igfs.secondaryFileSystemEnabled))
-            this.addDependency(deps, 'org.apache.ignite', 'ignite-hadoop', igniteVersion);
-
-        if (_.find(caches, blobStoreFactory))
-            this.addDependency(deps, 'org.apache.ignite', 'ignite-hibernate', igniteVersion);
-
-        if (cluster.logger && cluster.logger.kind) {
-            dep = POM_DEPENDENCIES[cluster.logger.kind];
-
-            if (dep)
-                this.addDependency(deps, 'org.apache.ignite', dep.artifactId, igniteVersion);
-        }
-
-        this.dependencies(res, cluster, deps.concat(storeDeps));
-
-        res.needEmptyLine = true;
-
-        this.build(res, cluster, excludeGroupIds);
-
-        return res;
-    }
-}
-
-export default ['GeneratorPom', GeneratorPom];

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/src/main/js/app/modules/configuration/generator/Xml.service.js
----------------------------------------------------------------------
diff --git a/modules/web-console/src/main/js/app/modules/configuration/generator/Xml.service.js b/modules/web-console/src/main/js/app/modules/configuration/generator/Xml.service.js
deleted file mode 100644
index 58d1ce0..0000000
--- a/modules/web-console/src/main/js/app/modules/configuration/generator/Xml.service.js
+++ /dev/null
@@ -1,21 +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.
- */
-
-// TODO IGNITE-2052: need move $generatorXml to services.
-export default ['GeneratorXml', () => {
-    return $generatorXml;
-}];

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/src/main/js/app/modules/configuration/sidebar.directive.js
----------------------------------------------------------------------
diff --git a/modules/web-console/src/main/js/app/modules/configuration/sidebar.directive.js b/modules/web-console/src/main/js/app/modules/configuration/sidebar.directive.js
deleted file mode 100644
index e51553b..0000000
--- a/modules/web-console/src/main/js/app/modules/configuration/sidebar.directive.js
+++ /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.
- */
-
-export default ['igniteSidebar', ['igniteSidebar', (igniteSidebar) => {
-    function controller() {
-        const ctrl = this;
-
-        ctrl.items = igniteSidebar;
-    }
-
-    return {
-        restrict: 'A',
-        controller,
-        controllerAs: 'sidebar'
-    };
-}]];

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/src/main/js/app/modules/dialog/dialog-content.directive.js
----------------------------------------------------------------------
diff --git a/modules/web-console/src/main/js/app/modules/dialog/dialog-content.directive.js b/modules/web-console/src/main/js/app/modules/dialog/dialog-content.directive.js
deleted file mode 100644
index 98e9903..0000000
--- a/modules/web-console/src/main/js/app/modules/dialog/dialog-content.directive.js
+++ /dev/null
@@ -1,31 +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 ['igniteDialogContent', [() => {
-    const link = ($scope, $element, $attrs, igniteDialog) => {
-        igniteDialog.content = $element.html();
-
-        $element.hide();
-    };
-
-    return {
-        scope: {},
-        restrict: 'E',
-        link,
-        require: '^igniteDialog'
-    };
-}]];

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/src/main/js/app/modules/dialog/dialog-title.directive.js
----------------------------------------------------------------------
diff --git a/modules/web-console/src/main/js/app/modules/dialog/dialog-title.directive.js b/modules/web-console/src/main/js/app/modules/dialog/dialog-title.directive.js
deleted file mode 100644
index ed4adb8..0000000
--- a/modules/web-console/src/main/js/app/modules/dialog/dialog-title.directive.js
+++ /dev/null
@@ -1,31 +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 ['igniteDialogTitle', [() => {
-    const link = ($scope, $element, $attrs, igniteDialog) => {
-        igniteDialog.title = $element.text();
-
-        $element.hide();
-    };
-
-    return {
-        scope: {},
-        restrict: 'E',
-        link,
-        require: '^igniteDialog'
-    };
-}]];

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/src/main/js/app/modules/dialog/dialog.controller.js
----------------------------------------------------------------------
diff --git a/modules/web-console/src/main/js/app/modules/dialog/dialog.controller.js b/modules/web-console/src/main/js/app/modules/dialog/dialog.controller.js
deleted file mode 100644
index 05518d3..0000000
--- a/modules/web-console/src/main/js/app/modules/dialog/dialog.controller.js
+++ /dev/null
@@ -1,40 +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 ['$rootScope', '$scope', 'IgniteDialog', function($root, $scope, IgniteDialog) {
-    const ctrl = this;
-
-    const dialog = new IgniteDialog({
-        scope: $scope
-    });
-
-    ctrl.show = () => {
-        dialog.$promise.then(dialog.show);
-    };
-
-    $scope.$watch(() => ctrl.title, () => {
-        $scope.title = ctrl.title;
-    });
-
-    $scope.$watch(() => ctrl.content, () => {
-        $scope.content = ctrl.content;
-    });
-
-    $root.$on('$stateChangeStart', () => {
-        dialog.hide();
-    });
-}];

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/src/main/js/app/modules/dialog/dialog.directive.js
----------------------------------------------------------------------
diff --git a/modules/web-console/src/main/js/app/modules/dialog/dialog.directive.js b/modules/web-console/src/main/js/app/modules/dialog/dialog.directive.js
deleted file mode 100644
index 7aab10f..0000000
--- a/modules/web-console/src/main/js/app/modules/dialog/dialog.directive.js
+++ /dev/null
@@ -1,32 +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 controller from './dialog.controller';
-
-const template = '<a ng-click="ctrl.show()"><span ng-transclude=""></span></a>';
-
-export default ['igniteDialog', [() => {
-    return {
-        restrict: 'E',
-        template,
-        controller,
-        controllerAs: 'ctrl',
-        replace: true,
-        transclude: true,
-        require: '^igniteDialog'
-    };
-}]];

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/src/main/js/app/modules/dialog/dialog.factory.js
----------------------------------------------------------------------
diff --git a/modules/web-console/src/main/js/app/modules/dialog/dialog.factory.js b/modules/web-console/src/main/js/app/modules/dialog/dialog.factory.js
deleted file mode 100644
index e15891f..0000000
--- a/modules/web-console/src/main/js/app/modules/dialog/dialog.factory.js
+++ /dev/null
@@ -1,32 +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 templateUrl from './dialog.jade';
-
-export default ['IgniteDialog', ['$modal', ($modal) => {
-    const defaults = {
-        templateUrl,
-        placement: 'center',
-        show: false
-    };
-
-    return function(options) {
-        options = _.extend({}, defaults, options);
-
-        return $modal(options);
-    };
-}]];

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/src/main/js/app/modules/dialog/dialog.jade
----------------------------------------------------------------------
diff --git a/modules/web-console/src/main/js/app/modules/dialog/dialog.jade b/modules/web-console/src/main/js/app/modules/dialog/dialog.jade
deleted file mode 100644
index 0043709..0000000
--- a/modules/web-console/src/main/js/app/modules/dialog/dialog.jade
+++ /dev/null
@@ -1,26 +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.
-
-.modal(tabindex='-1' role='dialog')
-    .modal-dialog
-        .modal-content
-            .modal-header
-                button.close(ng-click='$hide()' aria-hidden='true') &times;
-                h4.modal-title {{title}}
-            .modal-body(ng-show='content')
-                p(ng-bind-html='content' style='text-align: left;')
-            .modal-footer
-                button.btn.btn-primary(id='confirm-btn-confirm' ng-click='$hide()') Ok

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/src/main/js/app/modules/dialog/dialog.module.js
----------------------------------------------------------------------
diff --git a/modules/web-console/src/main/js/app/modules/dialog/dialog.module.js b/modules/web-console/src/main/js/app/modules/dialog/dialog.module.js
deleted file mode 100644
index c9ba9f9..0000000
--- a/modules/web-console/src/main/js/app/modules/dialog/dialog.module.js
+++ /dev/null
@@ -1,32 +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 angular from 'angular';
-
-import igniteDialog from './dialog.directive';
-import igniteDialogTitle from './dialog-title.directive';
-import igniteDialogContent from './dialog-content.directive';
-import IgniteDialog from './dialog.factory';
-
-angular
-.module('ignite-console.dialog', [
-
-])
-.factory(...IgniteDialog)
-.directive(...igniteDialog)
-.directive(...igniteDialogTitle)
-.directive(...igniteDialogContent);

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/src/main/js/app/modules/form/field/bs-select-placeholder.directive.js
----------------------------------------------------------------------
diff --git a/modules/web-console/src/main/js/app/modules/form/field/bs-select-placeholder.directive.js b/modules/web-console/src/main/js/app/modules/form/field/bs-select-placeholder.directive.js
deleted file mode 100644
index 83f438d..0000000
--- a/modules/web-console/src/main/js/app/modules/form/field/bs-select-placeholder.directive.js
+++ /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.
- */
-
-// Override AngularStrap "bsSelect" in order to dynamically change placeholder and class.
-export default ['bsSelect', [() => {
-    const link = (scope, $element, attrs, [ngModel]) => {
-        if (!ngModel)
-            return;
-
-        const $render = ngModel.$render;
-
-        ngModel.$render = () => {
-            $render();
-
-            const value = ngModel.$viewValue;
-
-            if (_.isNil(value) || (attrs.multiple && !value.length)) {
-                $element.html(attrs.placeholder);
-
-                $element.addClass('placeholder');
-            }
-            else
-                $element.removeClass('placeholder');
-        };
-    };
-
-    return {
-        priority: 1,
-        restrict: 'A',
-        link,
-        require: ['?ngModel']
-    };
-}]];

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/src/main/js/app/modules/form/field/down.directive.js
----------------------------------------------------------------------
diff --git a/modules/web-console/src/main/js/app/modules/form/field/down.directive.js b/modules/web-console/src/main/js/app/modules/form/field/down.directive.js
deleted file mode 100644
index 91be945..0000000
--- a/modules/web-console/src/main/js/app/modules/form/field/down.directive.js
+++ /dev/null
@@ -1,43 +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.
- */
-
-const template = '<i class="tipField fa fa-arrow-down ng-scope" ng-click="down()"></i>';
-
-export default ['igniteFormFieldDown', ['$tooltip', ($tooltip) => {
-    const link = (scope, $element) => {
-        $tooltip($element, { title: 'Move item down' });
-
-        scope.down = () => {
-            const i = scope.models.indexOf(scope.model);
-            scope.models.splice(i, 1);
-            scope.models.splice(i + 1, 0, scope.model);
-        };
-    };
-
-    return {
-        restrict: 'E',
-        scope: {
-            model: '=ngModel',
-            models: '=models'
-        },
-        template,
-        link,
-        replace: true,
-        transclude: true,
-        require: '^form'
-    };
-}]];

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/src/main/js/app/modules/form/field/dropdown.directive.js
----------------------------------------------------------------------
diff --git a/modules/web-console/src/main/js/app/modules/form/field/dropdown.directive.js b/modules/web-console/src/main/js/app/modules/form/field/dropdown.directive.js
deleted file mode 100644
index 23c900a..0000000
--- a/modules/web-console/src/main/js/app/modules/form/field/dropdown.directive.js
+++ /dev/null
@@ -1,83 +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 templateUrl from './dropdown.jade';
-
-export default ['igniteFormFieldDropdown', ['IgniteFormGUID', 'IgniteLegacyTable', (guid, LegacyTable) => {
-    const controller = () => {};
-
-    const link = (scope, $element, attrs, [form, label]) => {
-        const {id, name} = scope;
-
-        scope.id = id || guid();
-
-        if (label) {
-            label.for = scope.id;
-
-            scope.label = label;
-
-            scope.$watch('required', (required) => {
-                label.required = required || false;
-            });
-        }
-
-        form.$defaults = form.$defaults || {};
-        form.$defaults[name] = _.cloneDeep(scope.value);
-
-        const setAsDefault = () => {
-            if (!form.$pristine) return;
-
-            form.$defaults = form.$defaults || {};
-            form.$defaults[name] = _.cloneDeep(scope.value);
-        };
-
-        scope.$watch(() => form.$pristine, setAsDefault);
-        scope.$watch('value', setAsDefault);
-
-        scope.tableReset = () => {
-            LegacyTable.tableSaveAndReset();
-        };
-    };
-
-    return {
-        restrict: 'E',
-        scope: {
-            id: '@',
-            name: '@',
-            required: '=ngRequired',
-            value: '=ngModel',
-
-            focus: '=ngFocus',
-
-            onEnter: '@'
-        },
-        bindToController: {
-            value: '=ngModel',
-            placeholder: '@',
-            options: '=',
-            ngDisabled: '=',
-            multiple: '='
-        },
-        link,
-        templateUrl,
-        controller,
-        controllerAs: 'dropdown',
-        replace: true,
-        transclude: true,
-        require: ['^form', '?^igniteFormField']
-    };
-}]];

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/src/main/js/app/modules/form/field/dropdown.jade
----------------------------------------------------------------------
diff --git a/modules/web-console/src/main/js/app/modules/form/field/dropdown.jade b/modules/web-console/src/main/js/app/modules/form/field/dropdown.jade
deleted file mode 100644
index 5b7cdf6..0000000
--- a/modules/web-console/src/main/js/app/modules/form/field/dropdown.jade
+++ /dev/null
@@ -1,61 +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.
-
-.input-tip
-    button.select-toggle.form-control(
-        ng-if='dropdown.multiple'
-        id='{{ id }}'
-        name='{{ name }}'
-        data-placeholder='{{ dropdown.placeholder }}'
-
-        bs-select 
-        bs-options='item.value as item.label for item in dropdown.options' 
-        data-multiple='1'
-
-        ng-model='dropdown.value'
-        ng-disabled='dropdown.ngDisabled || !dropdown.options || !dropdown.options.length'
-
-        data-ng-required='required || false'
-
-        ignite-on-enter='{{ onEnter }}'
-
-        tabindex='0'
-
-        data-ng-focus='tableReset()'
-    )
-
-    button.select-toggle.form-control(
-        ng-if='!dropdown.multiple'
-        id='{{ id }}'
-        name='{{ name }}'
-        data-placeholder='{{ dropdown.placeholder }}'
-
-        bs-select
-        bs-options='item.value as item.label for item in dropdown.options' 
-
-        ng-model='dropdown.value'
-        ng-disabled='dropdown.ngDisabled || !dropdown.options || !dropdown.options.length'
-
-        data-ng-required='required || false'
-
-        ignite-on-enter='{{ onEnter }}'
-
-        tabindex='0'
-
-        data-ng-focus='tableReset()'
-    )
-
-    span(ng-transclude='')

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/src/main/js/app/modules/form/field/field.css
----------------------------------------------------------------------
diff --git a/modules/web-console/src/main/js/app/modules/form/field/field.css b/modules/web-console/src/main/js/app/modules/form/field/field.css
deleted file mode 100644
index 3ea64f4..0000000
--- a/modules/web-console/src/main/js/app/modules/form/field/field.css
+++ /dev/null
@@ -1,23 +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.
- */
-
-.indexField {
-    float: left;
-    line-height: 28px;
-    margin-right: 5px;
-    color: #ec1c24;
-}

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/src/main/js/app/modules/form/field/field.directive.js
----------------------------------------------------------------------
diff --git a/modules/web-console/src/main/js/app/modules/form/field/field.directive.js b/modules/web-console/src/main/js/app/modules/form/field/field.directive.js
deleted file mode 100644
index 630f74f..0000000
--- a/modules/web-console/src/main/js/app/modules/form/field/field.directive.js
+++ /dev/null
@@ -1,44 +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 templateUrl from './field.jade';
-import './field.css';
-
-export default ['igniteFormField', [() => {
-    const controller = [function() {
-        const ctrl = this;
-
-        ctrl.type = ctrl.type || 'external';
-    }];
-
-    return {
-        restrict: 'E',
-        scope: {},
-        bindToController: {
-            for: '@',
-            label: '@',
-            type: '@',
-            name: '@'
-        },
-        templateUrl,
-        controller,
-        controllerAs: 'field',
-        replace: true,
-        transclude: true,
-        require: '^form'
-    };
-}]];

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/src/main/js/app/modules/form/field/field.jade
----------------------------------------------------------------------
diff --git a/modules/web-console/src/main/js/app/modules/form/field/field.jade b/modules/web-console/src/main/js/app/modules/form/field/field.jade
deleted file mode 100644
index 08250ac..0000000
--- a/modules/web-console/src/main/js/app/modules/form/field/field.jade
+++ /dev/null
@@ -1,27 +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.
-
-div
-    div(ng-if='field.type == "external"')
-        label.col-xs-4.col-sm-4.col-md-4(
-            id='{{::field.for}}Label'
-            for='{{::field.for}}'
-            class='{{ field.required ? "required" : "" }}'
-        )
-            span(ng-if='field.label') {{::field.label}}:
-        .col-xs-8.col-sm-8.col-md-8(ng-transclude='')
-    div(ng-if='field.type == "internal"')
-        label.col-xs-12.col-sm-12.col-md-12(ng-transclude id='{{::field.for}}Label')


[43/52] ignite git commit: Web Console beta-3.

Posted by ak...@apache.org.
http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/backend/app/settings.js
----------------------------------------------------------------------
diff --git a/modules/web-console/backend/app/settings.js b/modules/web-console/backend/app/settings.js
new file mode 100644
index 0000000..b3609e8
--- /dev/null
+++ b/modules/web-console/backend/app/settings.js
@@ -0,0 +1,80 @@
+/*
+ * 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.
+ */
+
+'use strict';
+
+// Fire me up!
+
+/**
+ * Module with server-side configuration.
+ */
+module.exports = {
+    implements: 'settings',
+    inject: ['nconf', 'require(fs)']
+};
+
+module.exports.factory = function(nconf, fs) {
+    /**
+     * Normalize a port into a number, string, or false.
+     */
+    const _normalizePort = function(val) {
+        const port = parseInt(val, 10);
+
+        // named pipe
+        if (isNaN(port))
+            return val;
+
+        // port number
+        if (port >= 0)
+            return port;
+
+        return false;
+    };
+
+    const mailConfig = nconf.get('mail') || {};
+
+    return {
+        agent: {
+            dists: 'agent_dists',
+            port: _normalizePort(nconf.get('agentServer:port') || 3002),
+            legacyPort: _normalizePort(nconf.get('agentServer:legacyPort')),
+            SSLOptions: nconf.get('agentServer:ssl') && {
+                key: fs.readFileSync(nconf.get('agentServer:key')),
+                cert: fs.readFileSync(nconf.get('agentServer:cert')),
+                passphrase: nconf.get('agentServer:keyPassphrase')
+            }
+        },
+        server: {
+            port: _normalizePort(nconf.get('server:port') || 3000),
+            SSLOptions: nconf.get('server:ssl') && {
+                enable301Redirects: true,
+                trustXFPHeader: true,
+                key: fs.readFileSync(nconf.get('server:key')),
+                cert: fs.readFileSync(nconf.get('server:cert')),
+                passphrase: nconf.get('server:keyPassphrase')
+            }
+        },
+        smtp: {
+            ...mailConfig,
+            address: (username, email) => username ? '"' + username + '" <' + email + '>' : email
+        },
+        mongoUrl: nconf.get('mongodb:url') || 'mongodb://localhost/console',
+        cookieTTL: 3600000 * 24 * 30,
+        sessionSecret: nconf.get('server:sessionSecret') || 'keyboard cat',
+        tokenLength: 20
+    };
+};

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/backend/config/settings.json.sample
----------------------------------------------------------------------
diff --git a/modules/web-console/backend/config/settings.json.sample b/modules/web-console/backend/config/settings.json.sample
new file mode 100644
index 0000000..41f1152
--- /dev/null
+++ b/modules/web-console/backend/config/settings.json.sample
@@ -0,0 +1,30 @@
+{
+    "server": {
+        "port": 3000,
+        "sessionSecret": "CHANGE ME",
+        "ssl": false,
+        "key": "serve/keys/test.key",
+        "cert": "serve/keys/test.crt",
+        "keyPassphrase": "password"
+    },
+    "mongodb": {
+        "url": "mongodb://localhost/console"
+    },
+    "agentServer": {
+        "port": 3001,
+        "ssl": false,
+        "key": "serve/keys/test.key",
+        "cert": "serve/keys/test.crt",
+        "keyPassphrase": "password"
+    },
+    "mail": {
+        "service": "",
+        "sign": "Kind regards,<br>Apache Ignite Team",
+        "greeting": "Apache Ignite Web Console",
+        "from": "Apache Ignite Web Console <so...@somecompany.tld>",
+        "auth": {
+            "user": "someusername@somecompany.tld",
+            "pass": ""
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/backend/errors/AppErrorException.js
----------------------------------------------------------------------
diff --git a/modules/web-console/backend/errors/AppErrorException.js b/modules/web-console/backend/errors/AppErrorException.js
new file mode 100644
index 0000000..208b09b
--- /dev/null
+++ b/modules/web-console/backend/errors/AppErrorException.js
@@ -0,0 +1,36 @@
+/*
+ * 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.
+ */
+
+'use strict';
+
+class AppErrorException extends Error {
+    constructor(message) {
+        super(message);
+
+        this.name = this.constructor.name;
+        this.code = 400;
+        this.httpCode = 400;
+        this.message = message;
+
+        if (typeof Error.captureStackTrace === 'function')
+            Error.captureStackTrace(this, this.constructor);
+        else
+            this.stack = (new Error(message)).stack;
+    }
+}
+
+module.exports = AppErrorException;

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/backend/errors/AuthFailedException.js
----------------------------------------------------------------------
diff --git a/modules/web-console/backend/errors/AuthFailedException.js b/modules/web-console/backend/errors/AuthFailedException.js
new file mode 100644
index 0000000..3208e1d
--- /dev/null
+++ b/modules/web-console/backend/errors/AuthFailedException.js
@@ -0,0 +1,30 @@
+/*
+ * 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.
+ */
+
+'use strict';
+
+import AppErrorException from './AppErrorException';
+
+class AuthFailedException extends AppErrorException {
+    constructor(message) {
+        super(message);
+
+        this.httpCode = 401;
+    }
+}
+
+module.exports = AuthFailedException;

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/backend/errors/DuplicateKeyException.js
----------------------------------------------------------------------
diff --git a/modules/web-console/backend/errors/DuplicateKeyException.js b/modules/web-console/backend/errors/DuplicateKeyException.js
new file mode 100644
index 0000000..b228d0c
--- /dev/null
+++ b/modules/web-console/backend/errors/DuplicateKeyException.js
@@ -0,0 +1,28 @@
+/*
+ * 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.
+ */
+
+'use strict';
+
+import AppErrorException from './AppErrorException';
+
+class DuplicateKeyException extends AppErrorException {
+    constructor(message) {
+        super(message);
+    }
+}
+
+module.exports = DuplicateKeyException;

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/backend/errors/IllegalAccessError.js
----------------------------------------------------------------------
diff --git a/modules/web-console/backend/errors/IllegalAccessError.js b/modules/web-console/backend/errors/IllegalAccessError.js
new file mode 100644
index 0000000..4fcd2d4
--- /dev/null
+++ b/modules/web-console/backend/errors/IllegalAccessError.js
@@ -0,0 +1,29 @@
+/*
+ * 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.
+ */
+
+'use strict';
+
+import AppErrorException from './AppErrorException';
+
+class IllegalAccessError extends AppErrorException {
+    constructor(message) {
+        super(message);
+        this.httpCode = 401;
+    }
+}
+
+module.exports = IllegalAccessError;

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/backend/errors/IllegalArgumentException.js
----------------------------------------------------------------------
diff --git a/modules/web-console/backend/errors/IllegalArgumentException.js b/modules/web-console/backend/errors/IllegalArgumentException.js
new file mode 100644
index 0000000..0487d05
--- /dev/null
+++ b/modules/web-console/backend/errors/IllegalArgumentException.js
@@ -0,0 +1,29 @@
+/*
+ * 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.
+ */
+
+'use strict';
+
+import AppErrorException from './AppErrorException';
+
+class IllegalArgumentException extends AppErrorException {
+    constructor(message) {
+        super(message);
+        this.httpCode = 400;
+    }
+}
+
+module.exports = IllegalArgumentException;

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/backend/errors/MissingResourceException.js
----------------------------------------------------------------------
diff --git a/modules/web-console/backend/errors/MissingResourceException.js b/modules/web-console/backend/errors/MissingResourceException.js
new file mode 100644
index 0000000..799775b
--- /dev/null
+++ b/modules/web-console/backend/errors/MissingResourceException.js
@@ -0,0 +1,30 @@
+/*
+ * 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.
+ */
+
+'use strict';
+
+import AppErrorException from './AppErrorException';
+
+class MissingResourceException extends AppErrorException {
+    constructor(message) {
+        super(message);
+
+        this.httpCode = 404;
+    }
+}
+
+module.exports = MissingResourceException;

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/backend/errors/ServerErrorException.js
----------------------------------------------------------------------
diff --git a/modules/web-console/backend/errors/ServerErrorException.js b/modules/web-console/backend/errors/ServerErrorException.js
new file mode 100644
index 0000000..439755e
--- /dev/null
+++ b/modules/web-console/backend/errors/ServerErrorException.js
@@ -0,0 +1,36 @@
+/*
+ * 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.
+ */
+
+'use strict';
+
+class ServerErrorException extends Error {
+    constructor(message) {
+        super(message);
+
+        this.name = this.constructor.name;
+        this.code = 500;
+        this.httpCode = 500;
+        this.message = message;
+
+        if (typeof Error.captureStackTrace === 'function')
+            Error.captureStackTrace(this, this.constructor);
+        else
+            this.stack = (new Error(message)).stack;
+    }
+}
+
+module.exports = ServerErrorException;

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/backend/errors/index.js
----------------------------------------------------------------------
diff --git a/modules/web-console/backend/errors/index.js b/modules/web-console/backend/errors/index.js
new file mode 100644
index 0000000..0af5cd5
--- /dev/null
+++ b/modules/web-console/backend/errors/index.js
@@ -0,0 +1,39 @@
+/*
+ * 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.
+ */
+
+'use strict';
+
+// Fire me up!
+
+import AppErrorException from './AppErrorException';
+import IllegalArgumentException from './IllegalArgumentException';
+import DuplicateKeyException from './DuplicateKeyException';
+import ServerErrorException from './ServerErrorException';
+import MissingResourceException from './MissingResourceException';
+import AuthFailedException from './AuthFailedException';
+
+module.exports = {
+    implements: 'errors',
+    factory: () => ({
+        AppErrorException,
+        IllegalArgumentException,
+        DuplicateKeyException,
+        ServerErrorException,
+        MissingResourceException,
+        AuthFailedException
+    })
+};

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/backend/index.js
----------------------------------------------------------------------
diff --git a/modules/web-console/backend/index.js b/modules/web-console/backend/index.js
new file mode 100644
index 0000000..dcb3f41
--- /dev/null
+++ b/modules/web-console/backend/index.js
@@ -0,0 +1,19 @@
+/*
+ * 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.
+ */
+
+require('babel-core/register');
+require('./app/index.js');

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/backend/injector.js
----------------------------------------------------------------------
diff --git a/modules/web-console/backend/injector.js b/modules/web-console/backend/injector.js
new file mode 100644
index 0000000..62f8980
--- /dev/null
+++ b/modules/web-console/backend/injector.js
@@ -0,0 +1,30 @@
+/*
+ * 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 fireUp from 'fire-up';
+
+module.exports = fireUp.newInjector({
+    basePath: __dirname,
+    modules: [
+        './app/**/*.js',
+        './config/**/*.js',
+        './errors/**/*.js',
+        './middlewares/**/*.js',
+        './routes/**/*.js',
+        './services/**/*.js'
+    ]
+});

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/backend/middlewares/api.js
----------------------------------------------------------------------
diff --git a/modules/web-console/backend/middlewares/api.js b/modules/web-console/backend/middlewares/api.js
new file mode 100644
index 0000000..9c6395e
--- /dev/null
+++ b/modules/web-console/backend/middlewares/api.js
@@ -0,0 +1,44 @@
+/*
+ * 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.
+ */
+
+'use strict';
+
+// Fire me up!
+
+module.exports = {
+    implements: 'middlewares:api',
+    factory: () => {
+        return (req, res, next) => {
+            res.api = {
+                error(err) {
+                    // TODO: removed code from error
+                    res.status(err.httpCode || err.code || 500).send(err.message);
+                },
+                ok(data) {
+                    res.status(200).json(data);
+                },
+                serverError(err) {
+                    err.httpCode = 500;
+
+                    res.api.error(err);
+                }
+            };
+
+            next();
+        };
+    }
+};

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/backend/middlewares/host.js
----------------------------------------------------------------------
diff --git a/modules/web-console/backend/middlewares/host.js b/modules/web-console/backend/middlewares/host.js
new file mode 100644
index 0000000..5ddd918
--- /dev/null
+++ b/modules/web-console/backend/middlewares/host.js
@@ -0,0 +1,39 @@
+/*
+ * 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.
+ */
+
+'use strict';
+
+// Fire me up!
+
+module.exports = {
+    implements: 'middlewares:host',
+    factory: () => {
+        return (req, res, next) => {
+            req.origin = function() {
+                if (req.headers.origin)
+                    return req.headers.origin;
+
+                if (req.headers['x-forwarded-server'])
+                    return `${req.headers['x-forwarded-proto'] || 'http'}://${req.headers['x-forwarded-server']}`;
+
+                return `${req.protocol}://${req.get('host')}`;
+            };
+
+            next();
+        };
+    }
+};

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/backend/middlewares/user.js
----------------------------------------------------------------------
diff --git a/modules/web-console/backend/middlewares/user.js b/modules/web-console/backend/middlewares/user.js
new file mode 100644
index 0000000..8923211
--- /dev/null
+++ b/modules/web-console/backend/middlewares/user.js
@@ -0,0 +1,36 @@
+/*
+ * 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.
+ */
+
+'use strict';
+
+// Fire me up!
+
+module.exports = {
+    implements: 'middlewares:user',
+    factory: () => {
+        return (req, res, next) => {
+            req.currentUserId = function() {
+                if (req.session.viewedUser && req.user.admin)
+                    return req.session.viewedUser._id;
+
+                return req.user._id;
+            };
+
+            next();
+        };
+    }
+};

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/backend/package.json
----------------------------------------------------------------------
diff --git a/modules/web-console/backend/package.json b/modules/web-console/backend/package.json
new file mode 100644
index 0000000..598dc00
--- /dev/null
+++ b/modules/web-console/backend/package.json
@@ -0,0 +1,71 @@
+{
+  "name": "ignite-web-console",
+  "version": "1.0.0",
+  "description": "Interactive Web console for configuration, executing SQL queries and monitoring of Apache Ignite Cluster",
+  "private": true,
+  "scripts": {
+    "ci-test": "cross-env NODE_ENV=test CONFIG_PATH='./test/config/settings.json' mocha -u tdd --require babel-core/register --reporter mocha-teamcity-reporter --recursive ./test/unit",
+    "test": "cross-env NODE_ENV=test CONFIG_PATH='./test/config/settings.json' mocha -u tdd --require babel-core/register  --recursive ./test/unit",
+    "eslint": "eslint --env node --format node_modules/eslint-friendly-formatter ./ -- --eff-by-issue",
+    "start": "node ./index.js"
+  },
+  "author": "",
+  "contributors": [
+    {
+      "name": "",
+      "email": ""
+    }
+  ],
+  "license": "Apache-2.0",
+  "keywords": "grid",
+  "homepage": "https://ignite.apache.org/",
+  "engines": {
+    "npm": "^3.x.x",
+    "node": "^4.x.x"
+  },
+  "os": [
+    "darwin",
+    "linux",
+    "win32"
+  ],
+  "dependencies": {
+    "body-parser": "^1.15.0",
+    "connect-mongo": "^1.1.0",
+    "cookie-parser": "~1.4.0",
+    "es6-promise": "^3.0.2",
+    "express": "^4.14.0",
+    "express-session": "^1.12.0",
+    "fire-up": "^1.0.0",
+    "glob": "^7.0.3",
+    "jszip": "^3.0.0",
+    "lodash": "^4.8.2",
+    "mongoose": "^4.4.11",
+    "morgan": "^1.7.0",
+    "nconf": "^0.8.2",
+    "nodemailer": "^2.3.0",
+    "passport": "^0.3.2",
+    "passport-local": "^1.0.0",
+    "passport-local-mongoose": "^4.0.0",
+    "passport.socketio": "^3.6.1",
+    "socket.io": "^1.4.5",
+    "ws": "^0.8.0"
+  },
+  "devDependencies": {
+    "babel-core": "^6.7.6",
+    "babel-eslint": "^6.0.4",
+    "babel-plugin-add-module-exports": "^0.2.1",
+    "babel-plugin-transform-builtin-extend": "^1.1.0",
+    "babel-plugin-transform-runtime": "^6.7.5",
+    "babel-polyfill": "^6.7.4",
+    "babel-preset-es2015": "^6.9.0",
+    "babel-preset-stage-1": "^6.5.0",
+    "babel-runtime": "^6.6.1",
+    "chai": "^3.5.0",
+    "cross-env": "^1.0.7",
+    "eslint": "^2.9.0",
+    "eslint-friendly-formatter": "^2.0.5",
+    "jasmine-core": "^2.4.1",
+    "mocha": "~2.5.3",
+    "mocha-teamcity-reporter": "^1.0.0"
+  }
+}

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/backend/routes/admin.js
----------------------------------------------------------------------
diff --git a/modules/web-console/backend/routes/admin.js b/modules/web-console/backend/routes/admin.js
new file mode 100644
index 0000000..70736d0
--- /dev/null
+++ b/modules/web-console/backend/routes/admin.js
@@ -0,0 +1,84 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+'use strict';
+
+// Fire me up!
+
+module.exports = {
+    implements: 'routes/admin',
+    inject: ['require(lodash)', 'require(express)', 'settings', 'mongo', 'services/spaces', 'services/mails', 'services/sessions', 'services/users']
+};
+
+/**
+ * @param _
+ * @param express
+ * @param settings
+ * @param mongo
+ * @param spacesService
+ * @param {MailsService} mailsService
+ * @param {SessionsService} sessionsService
+ * @param {UsersService} usersService
+ * @returns {Promise}
+ */
+module.exports.factory = function(_, express, settings, mongo, spacesService, mailsService, sessionsService, usersService) {
+    return new Promise((factoryResolve) => {
+        const router = new express.Router();
+
+        /**
+         * Get list of user accounts.
+         */
+        router.post('/list', (req, res) => {
+            usersService.list()
+                .then(res.api.ok)
+                .catch(res.api.error);
+        });
+
+        // Remove user.
+        router.post('/remove', (req, res) => {
+            usersService.remove(req.origin(), req.body.userId)
+                .then(res.api.ok)
+                .catch(res.api.error);
+        });
+
+        // Save user.
+        router.post('/save', (req, res) => {
+            const params = req.body;
+
+            mongo.Account.findByIdAndUpdate(params.userId, {admin: params.adminFlag}).exec()
+                .then(res.api.ok)
+                .catch(res.api.error);
+        });
+
+        // Become user.
+        router.get('/become', (req, res) => {
+            sessionsService.become(req.session, req.query.viewedUserId)
+                .then(res.api.ok)
+                .catch(res.api.error);
+        });
+
+        // Revert to your identity.
+        router.get('/revert/identity', (req, res) => {
+            sessionsService.revert(req.session)
+                .then(res.api.ok)
+                .catch(res.api.error);
+        });
+
+        factoryResolve(router);
+    });
+};
+

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/backend/routes/agent.js
----------------------------------------------------------------------
diff --git a/modules/web-console/backend/routes/agent.js b/modules/web-console/backend/routes/agent.js
new file mode 100644
index 0000000..3f90fbd
--- /dev/null
+++ b/modules/web-console/backend/routes/agent.js
@@ -0,0 +1,53 @@
+/*
+ * 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.
+ */
+
+'use strict';
+
+// Fire me up!
+
+module.exports = {
+    implements: 'routes/agents',
+    inject: ['require(lodash)', 'require(express)', 'services/agents']
+};
+
+/**
+ * @param _
+ * @param express
+ * @param {AgentsService} agentsService
+ * @returns {Promise}
+ */
+module.exports.factory = function(_, express, agentsService) {
+    return new Promise((resolveFactory) => {
+        const router = new express.Router();
+
+        /* Get grid topology. */
+        router.get('/download/zip', (req, res) => {
+            const host = req.hostname.match(/:/g) ? req.hostname.slice(0, req.hostname.indexOf(':')) : req.hostname;
+
+            agentsService.getArchive(host, req.user.token)
+                .then(({fileName, buffer}) => {
+                    // Set the archive name.
+                    res.attachment(fileName);
+
+                    res.send(buffer);
+                })
+                .catch(res.api.error);
+        });
+
+        resolveFactory(router);
+    });
+};

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/backend/routes/caches.js
----------------------------------------------------------------------
diff --git a/modules/web-console/backend/routes/caches.js b/modules/web-console/backend/routes/caches.js
new file mode 100644
index 0000000..e040fda
--- /dev/null
+++ b/modules/web-console/backend/routes/caches.js
@@ -0,0 +1,65 @@
+/*
+ * 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.
+ */
+
+'use strict';
+
+// Fire me up!
+
+module.exports = {
+    implements: 'routes/caches',
+    inject: ['require(lodash)', 'require(express)', 'mongo', 'services/caches']
+};
+
+module.exports.factory = function(_, express, mongo, cachesService) {
+    return new Promise((factoryResolve) => {
+        const router = new express.Router();
+
+        /**
+         * Save cache.
+         */
+        router.post('/save', (req, res) => {
+            const cache = req.body;
+
+            cachesService.merge(cache)
+                .then((savedCache) => res.api.ok(savedCache._id))
+                .catch(res.api.error);
+        });
+
+        /**
+         * Remove cache by ._id.
+         */
+        router.post('/remove', (req, res) => {
+            const cacheId = req.body._id;
+
+            cachesService.remove(cacheId)
+                .then(res.api.ok)
+                .catch(res.api.error);
+        });
+
+        /**
+         * Remove all caches.
+         */
+        router.post('/remove/all', (req, res) => {
+            cachesService.removeAll(req.currentUserId(), req.header('IgniteDemoMode'))
+                .then(res.api.ok)
+                .catch(res.api.error);
+        });
+
+        factoryResolve(router);
+    });
+};
+

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/backend/routes/clusters.js
----------------------------------------------------------------------
diff --git a/modules/web-console/backend/routes/clusters.js b/modules/web-console/backend/routes/clusters.js
new file mode 100644
index 0000000..97a446a
--- /dev/null
+++ b/modules/web-console/backend/routes/clusters.js
@@ -0,0 +1,64 @@
+/*
+ * 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.
+ */
+
+'use strict';
+
+// Fire me up!
+
+module.exports = {
+    implements: 'routes/clusters',
+    inject: ['require(lodash)', 'require(express)', 'mongo', 'services/clusters']
+};
+
+module.exports.factory = function(_, express, mongo, clustersService) {
+    return new Promise((factoryResolve) => {
+        const router = new express.Router();
+
+        /**
+         * Save cluster.
+         */
+        router.post('/save', (req, res) => {
+            const cluster = req.body;
+
+            clustersService.merge(cluster)
+                .then((savedCluster) => res.api.ok(savedCluster._id))
+                .catch(res.api.error);
+        });
+
+        /**
+         * Remove cluster by ._id.
+         */
+        router.post('/remove', (req, res) => {
+            const clusterId = req.body._id;
+
+            clustersService.remove(clusterId)
+                .then(res.api.ok)
+                .catch(res.api.error);
+        });
+
+        /**
+         * Remove all clusters.
+         */
+        router.post('/remove/all', (req, res) => {
+            clustersService.removeAll(req.currentUserId(), req.header('IgniteDemoMode'))
+                .then(res.api.ok)
+                .catch(res.api.error);
+        });
+
+        factoryResolve(router);
+    });
+};

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/backend/routes/configuration.js
----------------------------------------------------------------------
diff --git a/modules/web-console/backend/routes/configuration.js b/modules/web-console/backend/routes/configuration.js
new file mode 100644
index 0000000..c3ff5d6
--- /dev/null
+++ b/modules/web-console/backend/routes/configuration.js
@@ -0,0 +1,41 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+'use strict';
+
+// Fire me up!
+
+module.exports = {
+    implements: 'routes/configurations',
+    inject: ['require(lodash)', 'require(express)', 'mongo', 'services/configurations']
+};
+
+module.exports.factory = function(_, express, mongo, configurationsService) {
+    return new Promise((factoryResolve) => {
+        const router = new express.Router();
+        /**
+         * Get all user configuration in current space.
+         */
+        router.get('/list', (req, res) => {
+            configurationsService.list(req.currentUserId(), req.header('IgniteDemoMode'))
+                .then(res.api.ok)
+                .catch(res.api.error);
+        });
+
+        factoryResolve(router);
+    });
+};

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/backend/routes/demo.js
----------------------------------------------------------------------
diff --git a/modules/web-console/backend/routes/demo.js b/modules/web-console/backend/routes/demo.js
new file mode 100644
index 0000000..724b5c1
--- /dev/null
+++ b/modules/web-console/backend/routes/demo.js
@@ -0,0 +1,133 @@
+/*
+ * 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.
+ */
+
+'use strict';
+
+// Fire me up!
+
+import clusters from './demo/clusters.json';
+import caches from './demo/caches.json';
+import domains from './demo/domains.json';
+import igfss from './demo/igfss.json';
+
+module.exports = {
+    implements: 'routes/demo',
+    inject: ['require(lodash)', 'require(express)', 'settings', 'mongo', 'services/spaces', 'errors']
+};
+
+module.exports.factory = (_, express, settings, mongo, spacesService, errors) => {
+    return new Promise((factoryResolve) => {
+        const router = new express.Router();
+
+        /**
+         * Reset demo configuration.
+         */
+        router.post('/reset', (req, res) => {
+            spacesService.spaces(req.user._id, true)
+                .then((spaces) => {
+                    if (spaces.length) {
+                        const spaceIds = spaces.map((space) => space._id);
+
+                        return Promise.all([
+                            mongo.Cluster.remove({space: {$in: spaceIds}}).exec(),
+                            mongo.Cache.remove({space: {$in: spaceIds}}).exec(),
+                            mongo.DomainModel.remove({space: {$in: spaceIds}}).exec(),
+                            mongo.Igfs.remove({space: {$in: spaceIds}}).exec()
+                        ]).then(() => spaces[0]);
+                    }
+                })
+                .catch((err) => {
+                    if (err instanceof errors.MissingResourceException)
+                        return spacesService.createDemoSpace(req.user._id);
+                })
+                .then((space) => {
+                    return Promise.all(_.map(clusters, (cluster) => {
+                        const clusterDoc = new mongo.Cluster(cluster);
+
+                        clusterDoc.space = space._id;
+
+                        return clusterDoc.save();
+                    }));
+                })
+                .then((clusterDocs) => {
+                    return _.map(clusterDocs, (cluster) => {
+                        const addCacheToCluster = (cacheDoc) => cluster.caches.push(cacheDoc._id);
+                        const addIgfsToCluster = (igfsDoc) => cluster.igfss.push(igfsDoc._id);
+
+                        if (cluster.name.endsWith('-caches')) {
+                            const cachePromises = _.map(caches, (cacheData) => {
+                                const cache = new mongo.Cache(cacheData);
+
+                                cache.space = cluster.space;
+                                cache.clusters.push(cluster._id);
+
+                                return cache.save()
+                                    .then((cacheDoc) => {
+                                        const domainData = _.find(domains, (item) =>
+                                            item.databaseTable === cacheDoc.name.slice(0, -5).toUpperCase());
+
+                                        if (domainData) {
+                                            const domain = new mongo.DomainModel(domainData);
+
+                                            domain.space = cacheDoc.space;
+                                            domain.caches.push(cacheDoc._id);
+
+                                            return domain.save()
+                                                .then((domainDoc) => {
+                                                    cacheDoc.domains.push(domainDoc._id);
+
+                                                    return cacheDoc.save();
+                                                });
+                                        }
+
+                                        return cacheDoc;
+                                    });
+                            });
+
+                            return Promise.all(cachePromises)
+                                .then((cacheDocs) => {
+                                    _.forEach(cacheDocs, addCacheToCluster);
+
+                                    return cluster.save();
+                                });
+                        }
+
+                        if (cluster.name.endsWith('-igfs')) {
+                            return Promise.all(_.map(igfss, (igfs) => {
+                                const igfsDoc = new mongo.Igfs(igfs);
+
+                                igfsDoc.space = cluster.space;
+                                igfsDoc.clusters.push(cluster._id);
+
+                                return igfsDoc.save();
+                            }))
+                            .then((igfsDocs) => {
+                                _.forEach(igfsDocs, addIgfsToCluster);
+
+                                return cluster.save();
+                            });
+                        }
+                    });
+                })
+                .then(() => res.sendStatus(200))
+                .catch((err) => res.status(500).send(err.message));
+        });
+
+        factoryResolve(router);
+    });
+};
+

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/backend/routes/demo/caches.json
----------------------------------------------------------------------
diff --git a/modules/web-console/backend/routes/demo/caches.json b/modules/web-console/backend/routes/demo/caches.json
new file mode 100644
index 0000000..f7a8690
--- /dev/null
+++ b/modules/web-console/backend/routes/demo/caches.json
@@ -0,0 +1,87 @@
+[
+  {
+    "name": "CarCache",
+    "cacheMode": "PARTITIONED",
+    "atomicityMode": "ATOMIC",
+    "readThrough": true,
+    "writeThrough": true,
+    "sqlFunctionClasses": [],
+    "cacheStoreFactory": {
+      "kind": "CacheJdbcPojoStoreFactory",
+      "CacheJdbcPojoStoreFactory": {
+        "dataSourceBean": "dsH2",
+        "dialect": "H2"
+      }
+    },
+    "domains": [],
+    "clusters": []
+  },
+  {
+    "name": "ParkingCache",
+    "cacheMode": "PARTITIONED",
+    "atomicityMode": "ATOMIC",
+    "readThrough": true,
+    "writeThrough": true,
+    "sqlFunctionClasses": [],
+    "cacheStoreFactory": {
+      "kind": "CacheJdbcPojoStoreFactory",
+      "CacheJdbcPojoStoreFactory": {
+        "dataSourceBean": "dsH2",
+        "dialect": "H2"
+      }
+    },
+    "domains": [],
+    "clusters": []
+  },
+  {
+    "name": "CountryCache",
+    "cacheMode": "PARTITIONED",
+    "atomicityMode": "ATOMIC",
+    "readThrough": true,
+    "writeThrough": true,
+    "sqlFunctionClasses": [],
+    "cacheStoreFactory": {
+      "kind": "CacheJdbcPojoStoreFactory",
+      "CacheJdbcPojoStoreFactory": {
+        "dataSourceBean": "dsH2",
+        "dialect": "H2"
+      }
+    },
+    "domains": [],
+    "clusters": []
+  },
+  {
+    "name": "DepartmentCache",
+    "cacheMode": "PARTITIONED",
+    "atomicityMode": "ATOMIC",
+    "readThrough": true,
+    "writeThrough": true,
+    "sqlFunctionClasses": [],
+    "cacheStoreFactory": {
+      "kind": "CacheJdbcPojoStoreFactory",
+      "CacheJdbcPojoStoreFactory": {
+        "dataSourceBean": "dsH2",
+        "dialect": "H2"
+      }
+    },
+    "domains": [],
+    "clusters": []
+  },
+  {
+    "name": "EmployeeCache",
+    "cacheMode": "PARTITIONED",
+    "atomicityMode": "ATOMIC",
+    "readThrough": true,
+    "writeThrough": true,
+    "sqlFunctionClasses": [],
+    "cacheStoreFactory": {
+      "kind": "CacheJdbcPojoStoreFactory",
+      "CacheJdbcPojoStoreFactory": {
+        "dataSourceBean": "dsH2",
+        "dialect": "H2"
+      }
+    },
+    "domains": [],
+    "clusters": []
+  }
+]

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/backend/routes/demo/clusters.json
----------------------------------------------------------------------
diff --git a/modules/web-console/backend/routes/demo/clusters.json b/modules/web-console/backend/routes/demo/clusters.json
new file mode 100644
index 0000000..014b519
--- /dev/null
+++ b/modules/web-console/backend/routes/demo/clusters.json
@@ -0,0 +1,50 @@
+[
+  {
+    "name": "cluster-igfs",
+    "connector": {
+      "noDelay": true
+    },
+    "communication": {
+      "tcpNoDelay": true
+    },
+    "igfss": [],
+    "caches": [],
+    "binaryConfiguration": {
+      "compactFooter": true,
+      "typeConfigurations": []
+    },
+    "discovery": {
+      "kind": "Multicast",
+      "Multicast": {
+        "addresses": ["127.0.0.1:47500..47510"]
+      },
+      "Vm": {
+        "addresses": ["127.0.0.1:47500..47510"]
+      }
+    }
+  },
+  {
+    "name": "cluster-caches",
+    "connector": {
+      "noDelay": true
+    },
+    "communication": {
+      "tcpNoDelay": true
+    },
+    "igfss": [],
+    "caches": [],
+    "binaryConfiguration": {
+      "compactFooter": true,
+      "typeConfigurations": []
+    },
+    "discovery": {
+      "kind": "Multicast",
+      "Multicast": {
+        "addresses": ["127.0.0.1:47500..47510"]
+      },
+      "Vm": {
+        "addresses": ["127.0.0.1:47500..47510"]
+      }
+    }
+  }
+]

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/backend/routes/demo/domains.json
----------------------------------------------------------------------
diff --git a/modules/web-console/backend/routes/demo/domains.json b/modules/web-console/backend/routes/demo/domains.json
new file mode 100644
index 0000000..980d8d1
--- /dev/null
+++ b/modules/web-console/backend/routes/demo/domains.json
@@ -0,0 +1,307 @@
+[
+  {
+    "keyType": "Integer",
+    "valueType": "model.Parking",
+    "queryMetadata": "Configuration",
+    "databaseSchema": "CARS",
+    "databaseTable": "PARKING",
+    "indexes": [],
+    "aliases": [],
+    "fields": [
+      {
+        "name": "name",
+        "className": "String"
+      },
+      {
+        "name": "capacity",
+        "className": "Integer"
+      }
+    ],
+    "valueFields": [
+      {
+        "databaseFieldName": "NAME",
+        "databaseFieldType": "VARCHAR",
+        "javaFieldName": "name",
+        "javaFieldType": "String"
+      },
+      {
+        "databaseFieldName": "CAPACITY",
+        "databaseFieldType": "INTEGER",
+        "javaFieldName": "capacity",
+        "javaFieldType": "int"
+      }
+    ],
+    "keyFields": [
+      {
+        "databaseFieldName": "ID",
+        "databaseFieldType": "INTEGER",
+        "javaFieldName": "id",
+        "javaFieldType": "int"
+      }
+    ],
+    "caches": []
+  },
+  {
+    "keyType": "Integer",
+    "valueType": "model.Department",
+    "queryMetadata": "Configuration",
+    "databaseSchema": "PUBLIC",
+    "databaseTable": "DEPARTMENT",
+    "indexes": [],
+    "aliases": [],
+    "fields": [
+      {
+        "name": "countryId",
+        "className": "Integer"
+      },
+      {
+        "name": "name",
+        "className": "String"
+      }
+    ],
+    "valueFields": [
+      {
+        "databaseFieldName": "COUNTRY_ID",
+        "databaseFieldType": "INTEGER",
+        "javaFieldName": "countryId",
+        "javaFieldType": "int"
+      },
+      {
+        "databaseFieldName": "NAME",
+        "databaseFieldType": "VARCHAR",
+        "javaFieldName": "name",
+        "javaFieldType": "String"
+      }
+    ],
+    "keyFields": [
+      {
+        "databaseFieldName": "ID",
+        "databaseFieldType": "INTEGER",
+        "javaFieldName": "id",
+        "javaFieldType": "int"
+      }
+    ],
+    "caches": []
+  },
+  {
+    "keyType": "Integer",
+    "valueType": "model.Employee",
+    "queryMetadata": "Configuration",
+    "databaseSchema": "PUBLIC",
+    "databaseTable": "EMPLOYEE",
+    "indexes": [
+      {
+        "name": "EMP_NAMES",
+        "indexType": "SORTED",
+        "fields": [
+          {
+            "name": "firstName",
+            "direction": true
+          },
+          {
+            "name": "lastName",
+            "direction": true
+          }
+        ]
+      },
+      {
+        "name": "EMP_SALARY",
+        "indexType": "SORTED",
+        "fields": [
+          {
+            "name": "salary",
+            "direction": true
+          }
+        ]
+      }
+    ],
+    "aliases": [],
+    "fields": [
+      {
+        "name": "departmentId",
+        "className": "Integer"
+      },
+      {
+        "name": "managerId",
+        "className": "Integer"
+      },
+      {
+        "name": "firstName",
+        "className": "String"
+      },
+      {
+        "name": "lastName",
+        "className": "String"
+      },
+      {
+        "name": "email",
+        "className": "String"
+      },
+      {
+        "name": "phoneNumber",
+        "className": "String"
+      },
+      {
+        "name": "hireDate",
+        "className": "Date"
+      },
+      {
+        "name": "job",
+        "className": "String"
+      },
+      {
+        "name": "salary",
+        "className": "Double"
+      }
+    ],
+    "valueFields": [
+      {
+        "databaseFieldName": "DEPARTMENT_ID",
+        "databaseFieldType": "INTEGER",
+        "javaFieldName": "departmentId",
+        "javaFieldType": "int"
+      },
+      {
+        "databaseFieldName": "MANAGER_ID",
+        "databaseFieldType": "INTEGER",
+        "javaFieldName": "managerId",
+        "javaFieldType": "Integer"
+      },
+      {
+        "databaseFieldName": "FIRST_NAME",
+        "databaseFieldType": "VARCHAR",
+        "javaFieldName": "firstName",
+        "javaFieldType": "String"
+      },
+      {
+        "databaseFieldName": "LAST_NAME",
+        "databaseFieldType": "VARCHAR",
+        "javaFieldName": "lastName",
+        "javaFieldType": "String"
+      },
+      {
+        "databaseFieldName": "EMAIL",
+        "databaseFieldType": "VARCHAR",
+        "javaFieldName": "email",
+        "javaFieldType": "String"
+      },
+      {
+        "databaseFieldName": "PHONE_NUMBER",
+        "databaseFieldType": "VARCHAR",
+        "javaFieldName": "phoneNumber",
+        "javaFieldType": "String"
+      },
+      {
+        "databaseFieldName": "HIRE_DATE",
+        "databaseFieldType": "DATE",
+        "javaFieldName": "hireDate",
+        "javaFieldType": "Date"
+      },
+      {
+        "databaseFieldName": "JOB",
+        "databaseFieldType": "VARCHAR",
+        "javaFieldName": "job",
+        "javaFieldType": "String"
+      },
+      {
+        "databaseFieldName": "SALARY",
+        "databaseFieldType": "DOUBLE",
+        "javaFieldName": "salary",
+        "javaFieldType": "Double"
+      }
+    ],
+    "keyFields": [
+      {
+        "databaseFieldName": "ID",
+        "databaseFieldType": "INTEGER",
+        "javaFieldName": "id",
+        "javaFieldType": "int"
+      }
+    ],
+    "caches": []
+  },
+  {
+    "keyType": "Integer",
+    "valueType": "model.Country",
+    "queryMetadata": "Configuration",
+    "databaseSchema": "PUBLIC",
+    "databaseTable": "COUNTRY",
+    "indexes": [],
+    "aliases": [],
+    "fields": [
+      {
+        "name": "name",
+        "className": "String"
+      },
+      {
+        "name": "population",
+        "className": "Integer"
+      }
+    ],
+    "valueFields": [
+      {
+        "databaseFieldName": "NAME",
+        "databaseFieldType": "VARCHAR",
+        "javaFieldName": "name",
+        "javaFieldType": "String"
+      },
+      {
+        "databaseFieldName": "POPULATION",
+        "databaseFieldType": "INTEGER",
+        "javaFieldName": "population",
+        "javaFieldType": "int"
+      }
+    ],
+    "keyFields": [
+      {
+        "databaseFieldName": "ID",
+        "databaseFieldType": "INTEGER",
+        "javaFieldName": "id",
+        "javaFieldType": "int"
+      }
+    ],
+    "caches": []
+  },
+  {
+    "keyType": "Integer",
+    "valueType": "model.Car",
+    "queryMetadata": "Configuration",
+    "databaseSchema": "CARS",
+    "databaseTable": "CAR",
+    "indexes": [],
+    "aliases": [],
+    "fields": [
+      {
+        "name": "parkingId",
+        "className": "Integer"
+      },
+      {
+        "name": "name",
+        "className": "String"
+      }
+    ],
+    "valueFields": [
+      {
+        "databaseFieldName": "PARKING_ID",
+        "databaseFieldType": "INTEGER",
+        "javaFieldName": "parkingId",
+        "javaFieldType": "int"
+      },
+      {
+        "databaseFieldName": "NAME",
+        "databaseFieldType": "VARCHAR",
+        "javaFieldName": "name",
+        "javaFieldType": "String"
+      }
+    ],
+    "keyFields": [
+      {
+        "databaseFieldName": "ID",
+        "databaseFieldType": "INTEGER",
+        "javaFieldName": "id",
+        "javaFieldType": "int"
+      }
+    ],
+    "caches": []
+  }
+]

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/backend/routes/demo/igfss.json
----------------------------------------------------------------------
diff --git a/modules/web-console/backend/routes/demo/igfss.json b/modules/web-console/backend/routes/demo/igfss.json
new file mode 100644
index 0000000..cd128a6
--- /dev/null
+++ b/modules/web-console/backend/routes/demo/igfss.json
@@ -0,0 +1,10 @@
+[
+  {
+    "ipcEndpointEnabled": true,
+    "fragmentizerEnabled": true,
+    "name": "igfs",
+    "dataCacheName": "igfs-data",
+    "metaCacheName": "igfs-meta",
+    "clusters": []
+  }
+]

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/backend/routes/domains.js
----------------------------------------------------------------------
diff --git a/modules/web-console/backend/routes/domains.js b/modules/web-console/backend/routes/domains.js
new file mode 100644
index 0000000..db1d892
--- /dev/null
+++ b/modules/web-console/backend/routes/domains.js
@@ -0,0 +1,76 @@
+/*
+ * 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.
+ */
+
+'use strict';
+
+// Fire me up!
+
+module.exports = {
+    implements: 'routes/domains',
+    inject: ['require(lodash)', 'require(express)', 'mongo', 'services/domains']
+};
+
+module.exports.factory = (_, express, mongo, domainsService) => {
+    return new Promise((factoryResolve) => {
+        const router = new express.Router();
+
+        /**
+         * Save domain model.
+         */
+        router.post('/save', (req, res) => {
+            const domain = req.body;
+
+            domainsService.batchMerge([domain])
+                .then(res.api.ok)
+                .catch(res.api.error);
+        });
+
+        /**
+         * Batch save domain models.
+         */
+        router.post('/save/batch', (req, res) => {
+            const domains = req.body;
+
+            domainsService.batchMerge(domains)
+                .then(res.api.ok)
+                .catch(res.api.error);
+        });
+
+        /**
+         * Remove domain model by ._id.
+         */
+        router.post('/remove', (req, res) => {
+            const domainId = req.body._id;
+
+            domainsService.remove(domainId)
+                .then(res.api.ok)
+                .catch(res.api.error);
+        });
+
+        /**
+         * Remove all domain models.
+         */
+        router.post('/remove/all', (req, res) => {
+            domainsService.removeAll(req.currentUserId(), req.header('IgniteDemoMode'))
+                .then(res.api.ok)
+                .catch(res.api.error);
+        });
+
+        factoryResolve(router);
+    });
+};
+

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/backend/routes/igfss.js
----------------------------------------------------------------------
diff --git a/modules/web-console/backend/routes/igfss.js b/modules/web-console/backend/routes/igfss.js
new file mode 100644
index 0000000..c88d627
--- /dev/null
+++ b/modules/web-console/backend/routes/igfss.js
@@ -0,0 +1,65 @@
+/*
+ * 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.
+ */
+
+'use strict';
+
+// Fire me up!
+
+module.exports = {
+    implements: 'routes/igfss',
+    inject: ['require(lodash)', 'require(express)', 'mongo', 'services/igfss']
+};
+
+module.exports.factory = function(_, express, mongo, igfssService) {
+    return new Promise((factoryResolve) => {
+        const router = new express.Router();
+
+        /**
+         * Save IGFS.
+         */
+        router.post('/save', (req, res) => {
+            const igfs = req.body;
+
+            igfssService.merge(igfs)
+                .then((savedIgfs) => res.api.ok(savedIgfs._id))
+                .catch(res.api.error);
+        });
+
+        /**
+         * Remove IGFS by ._id.
+         */
+        router.post('/remove', (req, res) => {
+            const igfsId = req.body._id;
+
+            igfssService.remove(igfsId)
+                .then(res.api.ok)
+                .catch(res.api.error);
+        });
+
+        /**
+         * Remove all IGFSs.
+         */
+        router.post('/remove/all', (req, res) => {
+            igfssService.removeAll(req.currentUserId(), req.header('IgniteDemoMode'))
+                .then(res.api.ok)
+                .catch(res.api.error);
+        });
+
+        factoryResolve(router);
+    });
+};
+

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/backend/routes/notebooks.js
----------------------------------------------------------------------
diff --git a/modules/web-console/backend/routes/notebooks.js b/modules/web-console/backend/routes/notebooks.js
new file mode 100644
index 0000000..c330809
--- /dev/null
+++ b/modules/web-console/backend/routes/notebooks.js
@@ -0,0 +1,80 @@
+/*
+ * 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.
+ */
+
+'use strict';
+
+// Fire me up!
+
+module.exports = {
+    implements: 'routes/notebooks',
+    inject: ['require(lodash)', 'require(express)', 'mongo', 'services/spaces', 'services/notebooks']
+};
+
+module.exports.factory = (_, express, mongo, spacesService, notebooksService) => {
+    return new Promise((factoryResolve) => {
+        const router = new express.Router();
+
+        /**
+         * Get notebooks names accessed for user account.
+         *
+         * @param req Request.
+         * @param res Response.
+         */
+        router.get('/', (req, res) => {
+            return spacesService.spaces(req.currentUserId())
+                .then((spaces) => _.map(spaces, (space) => space._id))
+                .then((spaceIds) => notebooksService.listBySpaces(spaceIds))
+                .then(res.api.ok)
+                .catch(res.api.error);
+        });
+
+        /**
+         * Save notebook accessed for user account.
+         *
+         * @param req Request.
+         * @param res Response.
+         */
+        router.post('/save', (req, res) => {
+            const notebook = req.body;
+
+            spacesService.spaceIds(req.currentUserId())
+                .then((spaceIds) => {
+                    notebook.space = notebook.space || spaceIds[0];
+
+                    return notebooksService.merge(notebook);
+                })
+                .then(res.api.ok)
+                .catch(res.api.error);
+        });
+
+        /**
+         * Remove notebook by ._id.
+         *
+         * @param req Request.
+         * @param res Response.
+         */
+        router.post('/remove', (req, res) => {
+            const notebookId = req.body._id;
+
+            notebooksService.remove(notebookId)
+                .then(res.api.ok)
+                .catch(res.api.error);
+        });
+
+        factoryResolve(router);
+    });
+};

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/backend/routes/profile.js
----------------------------------------------------------------------
diff --git a/modules/web-console/backend/routes/profile.js b/modules/web-console/backend/routes/profile.js
new file mode 100644
index 0000000..4d01cda
--- /dev/null
+++ b/modules/web-console/backend/routes/profile.js
@@ -0,0 +1,73 @@
+/*
+ * 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.
+ */
+
+'use strict';
+
+// Fire me up!
+
+module.exports = {
+    implements: 'routes/profiles',
+    inject: ['require(lodash)', 'require(express)', 'mongo', 'services/users']
+};
+
+/**
+ *
+ * @param _ Lodash module
+ * @param express Express module
+ * @param mongo
+ * @param {UsersService} usersService
+ * @returns {Promise}
+ */
+module.exports.factory = function(_, express, mongo, usersService) {
+    return new Promise((resolveFactory) => {
+        const router = new express.Router();
+
+        /**
+         * Save user profile.
+         */
+        router.post('/save', (req, res) => {
+            if (req.body.password && _.isEmpty(req.body.password))
+                return res.status(500).send('Wrong value for new password!');
+
+            usersService.save(req.body)
+                .then((user) => {
+                    const becomeUsed = req.session.viewedUser && user.admin;
+
+                    if (becomeUsed) {
+                        req.session.viewedUser = user;
+
+                        return user;
+                    }
+
+                    return new Promise((resolve, reject) => {
+                        req.logout();
+
+                        req.logIn(user, {}, (errLogIn) => {
+                            if (errLogIn)
+                                return reject(errLogIn);
+
+                            return resolve(user);
+                        });
+                    });
+                })
+                .then(res.api.ok)
+                .catch(res.api.error);
+        });
+
+        resolveFactory(router);
+    });
+};

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/backend/routes/public.js
----------------------------------------------------------------------
diff --git a/modules/web-console/backend/routes/public.js b/modules/web-console/backend/routes/public.js
new file mode 100644
index 0000000..5aad11a
--- /dev/null
+++ b/modules/web-console/backend/routes/public.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.
+ */
+
+'use strict';
+
+// Fire me up!
+
+module.exports = {
+    implements: 'routes/public',
+    inject: ['require(express)', 'require(passport)', 'settings', 'mongo', 'services/mails', 'services/users']
+};
+
+/**
+ *
+ * @param express
+ * @param passport
+ * @param settings
+ * @param mongo
+ * @param mailsService
+ * @param {UsersService} usersService
+ * @returns {Promise}
+ */
+module.exports.factory = function(express, passport, settings, mongo, mailsService, usersService) {
+    return new Promise((factoryResolve) => {
+        const router = new express.Router();
+
+        const _randomString = () => {
+            const possible = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';
+            const possibleLen = possible.length;
+
+            let res = '';
+
+            for (let i = 0; i < settings.tokenLength; i++)
+                res += possible.charAt(Math.floor(Math.random() * possibleLen));
+
+            return res;
+        };
+
+        // GET user.
+        router.post('/user', (req, res) => {
+            usersService.get(req.user, req.session.viewedUser)
+                .then(res.api.ok)
+                .catch(res.api.error);
+        });
+
+        /**
+         * Register new account.
+         */
+        router.post('/signup', (req, res) => {
+            usersService.create(req.origin(), req.body)
+                .then((user) => new Promise((resolve, reject) => {
+                    req.logIn(user, {}, (err) => {
+                        if (err)
+                            reject(err);
+
+                        resolve(user);
+                    });
+                }))
+                .then(res.api.ok)
+                .catch(res.api.error);
+        });
+
+        /**
+         * Sign in into exist account.
+         */
+        router.post('/signin', (req, res, next) => {
+            passport.authenticate('local', (errAuth, user) => {
+                if (errAuth)
+                    return res.status(401).send(errAuth.message);
+
+                if (!user)
+                    return res.status(401).send('Invalid email or password');
+
+                req.logIn(user, {}, (errLogIn) => {
+                    if (errLogIn)
+                        return res.status(401).send(errLogIn.message);
+
+                    return res.sendStatus(200);
+                });
+            })(req, res, next);
+        });
+
+        /**
+         * Logout.
+         */
+        router.post('/logout', (req, res) => {
+            req.logout();
+
+            res.sendStatus(200);
+        });
+
+        /**
+         * Send e-mail to user with reset token.
+         */
+        router.post('/password/forgot', (req, res) => {
+            mongo.Account.findOne({email: req.body.email}).exec()
+                .then((user) => {
+                    if (!user)
+                        throw new Error('Account with that email address does not exists!');
+
+                    user.resetPasswordToken = _randomString();
+
+                    return user.save();
+                })
+                .then((user) => mailsService.emailUserResetLink(req.origin(), user))
+                .then(() => res.status(200).send('An email has been sent with further instructions.'))
+                .catch((err) => {
+                    // TODO IGNITE-843 Send email to admin
+                    return res.status(401).send(err.message);
+                });
+        });
+
+        /**
+         * Change password with given token.
+         */
+        router.post('/password/reset', (req, res) => {
+            mongo.Account.findOne({resetPasswordToken: req.body.token}).exec()
+                .then((user) => {
+                    if (!user)
+                        throw new Error('Failed to find account with this token! Please check link from email.');
+
+                    return new Promise((resolve, reject) => {
+                        user.setPassword(req.body.password, (err, _user) => {
+                            if (err)
+                                return reject(new Error('Failed to reset password: ' + err.message));
+
+                            _user.resetPasswordToken = undefined; // eslint-disable-line no-undefined
+
+                            resolve(_user.save());
+                        });
+                    });
+                })
+                .then((user) => mailsService.emailPasswordChanged(req.origin(), user))
+                .then((user) => res.status(200).send(user.email))
+                .catch((err) => res.status(401).send(err.message));
+        });
+
+        /* GET reset password page. */
+        router.post('/password/validate/token', (req, res) => {
+            const token = req.body.token;
+
+            mongo.Account.findOne({resetPasswordToken: token}).exec()
+                .then((user) => {
+                    if (!user)
+                        throw new Error('Invalid token for password reset!');
+
+                    return res.json({token, email: user.email});
+                })
+                .catch((err) => res.status(401).send(err.message));
+        });
+
+        factoryResolve(router);
+    });
+};

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/backend/services/agents.js
----------------------------------------------------------------------
diff --git a/modules/web-console/backend/services/agents.js b/modules/web-console/backend/services/agents.js
new file mode 100644
index 0000000..8a65739
--- /dev/null
+++ b/modules/web-console/backend/services/agents.js
@@ -0,0 +1,82 @@
+/*
+ * 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.
+ */
+
+'use strict';
+
+// Fire me up!
+
+module.exports = {
+    implements: 'services/agents',
+    inject: ['require(lodash)', 'require(fs)', 'require(path)', 'require(jszip)', 'settings', 'agent-manager', 'errors']
+};
+
+/**
+ * @param _
+ * @param fs
+ * @param path
+ * @param JSZip
+ * @param settings
+ * @param agentMgr
+ * @param errors
+ * @returns {AgentsService}
+ */
+module.exports.factory = (_, fs, path, JSZip, settings, agentMgr, errors) => {
+    class AgentsService {
+        /**
+         * Get agent archive with user agent configuration.
+         * @returns {*} - readable stream for further piping. (http://stuk.github.io/jszip/documentation/api_jszip/generate_node_stream.html)
+         */
+        static getArchive(host, token) {
+            const latest = agentMgr.supportedAgents.latest;
+
+            if (_.isEmpty(latest))
+                throw new errors.MissingResourceException('Missing agent zip on server. Please ask webmaster to upload agent zip!');
+
+            const filePath = latest.filePath;
+            const fileName = latest.fileName;
+
+            const folder = path.basename(latest.fileName, '.zip');
+
+            // Read a zip file.
+            return new Promise((resolve, reject) => {
+                fs.readFile(filePath, (errFs, data) => {
+                    if (errFs)
+                        reject(new errors.ServerErrorException(errFs));
+
+                    JSZip.loadAsync(data)
+                        .then((zip) => {
+                            const prop = [];
+
+                            prop.push('tokens=' + token);
+                            prop.push('server-uri=' + (settings.agent.SSLOptions ? 'https' : 'http') + '://' + host + ':' + settings.agent.port);
+                            prop.push('#Uncomment following options if needed:');
+                            prop.push('#node-uri=http://localhost:8080');
+                            prop.push('#driver-folder=./jdbc-drivers');
+
+                            zip.file(folder + '/default.properties', prop.join('\n'));
+
+                            return zip.generateAsync({type: 'nodebuffer', platform: 'UNIX'})
+                                .then((buffer) => resolve({filePath, fileName, buffer}));
+                        })
+                        .catch(reject);
+                });
+            });
+        }
+    }
+
+    return AgentsService;
+};

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/backend/services/auth.js
----------------------------------------------------------------------
diff --git a/modules/web-console/backend/services/auth.js b/modules/web-console/backend/services/auth.js
new file mode 100644
index 0000000..9f7d77d
--- /dev/null
+++ b/modules/web-console/backend/services/auth.js
@@ -0,0 +1,47 @@
+/*
+ * 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.
+ */
+
+'use strict';
+
+// Fire me up!
+
+module.exports = {
+    implements: 'services/auth',
+    inject: ['require(lodash)', 'mongo', 'services/spaces', 'errors']
+};
+
+/**
+ * @param _
+ * @param mongo
+ * @param {SpacesService} spacesService
+ * @param errors
+ * @returns {AuthService}
+ */
+module.exports.factory = (_, mongo, spacesService, errors) => {
+    class AuthService {
+        // TODO IGNITE-3774: move implementation from public router.
+        static resetPassword() {
+
+        }
+
+        static validateResetToken() {
+
+        }
+    }
+
+    return AuthService;
+};

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/backend/services/caches.js
----------------------------------------------------------------------
diff --git a/modules/web-console/backend/services/caches.js b/modules/web-console/backend/services/caches.js
new file mode 100644
index 0000000..f8cc2ed
--- /dev/null
+++ b/modules/web-console/backend/services/caches.js
@@ -0,0 +1,144 @@
+/*
+ * 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.
+ */
+
+'use strict';
+
+// Fire me up!
+
+module.exports = {
+    implements: 'services/caches',
+    inject: ['require(lodash)', 'mongo', 'services/spaces', 'errors']
+};
+
+/**
+ * @param _
+ * @param mongo
+ * @param {SpacesService} spaceService
+ * @param errors
+ * @returns {CachesService}
+ */
+module.exports.factory = (_, mongo, spaceService, errors) => {
+    /**
+     * Convert remove status operation to own presentation.
+     * @param {RemoveResult} result - The results of remove operation.
+     */
+    const convertRemoveStatus = ({result}) => ({rowsAffected: result.n});
+
+    /**
+     * Update existing cache
+     * @param {Object} cache - The cache for updating
+     * @returns {Promise.<mongo.ObjectId>} that resolves cache id
+     */
+    const update = (cache) => {
+        const cacheId = cache._id;
+
+        return mongo.Cache.update({_id: cacheId}, cache, {upsert: true}).exec()
+            .then(() => mongo.Cluster.update({_id: {$in: cache.clusters}}, {$addToSet: {caches: cacheId}}, {multi: true}).exec())
+            .then(() => mongo.Cluster.update({_id: {$nin: cache.clusters}}, {$pull: {caches: cacheId}}, {multi: true}).exec())
+            .then(() => mongo.DomainModel.update({_id: {$in: cache.domains}}, {$addToSet: {caches: cacheId}}, {multi: true}).exec())
+            .then(() => mongo.DomainModel.update({_id: {$nin: cache.domains}}, {$pull: {caches: cacheId}}, {multi: true}).exec())
+            .then(() => cache)
+            .catch((err) => {
+                if (err.code === mongo.errCodes.DUPLICATE_KEY_UPDATE_ERROR || err.code === mongo.errCodes.DUPLICATE_KEY_ERROR)
+                    throw new errors.DuplicateKeyException('Cache with name: "' + cache.name + '" already exist.');
+            });
+    };
+
+    /**
+     * Create new cache.
+     * @param {Object} cache - The cache for creation.
+     * @returns {Promise.<mongo.ObjectId>} that resolves cache id.
+     */
+    const create = (cache) => {
+        return mongo.Cache.create(cache)
+            .then((savedCache) =>
+                mongo.Cluster.update({_id: {$in: savedCache.clusters}}, {$addToSet: {caches: savedCache._id}}, {multi: true}).exec()
+                    .then(() => mongo.DomainModel.update({_id: {$in: savedCache.domains}}, {$addToSet: {caches: savedCache._id}}, {multi: true}).exec())
+                    .then(() => savedCache)
+            )
+            .catch((err) => {
+                if (err.code === mongo.errCodes.DUPLICATE_KEY_ERROR)
+                    throw new errors.DuplicateKeyException('Cache with name: "' + cache.name + '" already exist.');
+            });
+    };
+
+    /**
+     * Remove all caches by space ids.
+     * @param {Number[]} spaceIds - The space ids for cache deletion.
+     * @returns {Promise.<RemoveResult>} - that resolves results of remove operation.
+     */
+    const removeAllBySpaces = (spaceIds) => {
+        return mongo.Cluster.update({space: {$in: spaceIds}}, {caches: []}, {multi: true}).exec()
+            .then(() => mongo.DomainModel.update({space: {$in: spaceIds}}, {caches: []}, {multi: true}).exec())
+            .then(() => mongo.Cache.remove({space: {$in: spaceIds}}).exec());
+    };
+
+    /**
+     * Service for manipulate Cache entities.
+     */
+    class CachesService {
+        /**
+         * Create or update cache.
+         * @param {Object} cache - The cache.
+         * @returns {Promise.<mongo.ObjectId>} that resolves cache id of merge operation.
+         */
+        static merge(cache) {
+            if (cache._id)
+                return update(cache);
+
+            return create(cache);
+        }
+
+        /**
+         * Get caches by spaces.
+         * @param {mongo.ObjectId|String} spaceIds - The spaces ids that own caches.
+         * @returns {Promise.<mongo.Cache[]>} - contains requested caches.
+         */
+        static listBySpaces(spaceIds) {
+            return mongo.Cache.find({space: {$in: spaceIds}}).sort('name').lean().exec();
+        }
+
+        /**
+         * Remove cache.
+         * @param {mongo.ObjectId|String} cacheId - The cache id for remove.
+         * @returns {Promise.<{rowsAffected}>} - The number of affected rows.
+         */
+        static remove(cacheId) {
+            if (_.isNil(cacheId))
+                return Promise.reject(new errors.IllegalArgumentException('Cache id can not be undefined or null'));
+
+            return mongo.Cluster.update({caches: {$in: [cacheId]}}, {$pull: {caches: cacheId}}, {multi: true}).exec()
+                .then(() => mongo.DomainModel.update({caches: {$in: [cacheId]}}, {$pull: {caches: cacheId}}, {multi: true}).exec())
+                .then(() => mongo.Cache.remove({_id: cacheId}).exec())
+                .then(convertRemoveStatus);
+        }
+
+        /**
+         * Remove all caches by user.
+         * @param {mongo.ObjectId|String} userId - The user id that own caches.
+         * @param {Boolean} demo - The flag indicates that need lookup in demo space.
+         * @returns {Promise.<{rowsAffected}>} - The number of affected rows.
+         */
+        static removeAll(userId, demo) {
+            return spaceService.spaceIds(userId, demo)
+                .then(removeAllBySpaces)
+                .then(convertRemoveStatus);
+        }
+    }
+
+    return CachesService;
+};


[30/52] ignite git commit: Web Console beta-3.

Posted by ak...@apache.org.
http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/frontend/controllers/clusters-controller.js
----------------------------------------------------------------------
diff --git a/modules/web-console/frontend/controllers/clusters-controller.js b/modules/web-console/frontend/controllers/clusters-controller.js
new file mode 100644
index 0000000..5a3c7e2
--- /dev/null
+++ b/modules/web-console/frontend/controllers/clusters-controller.js
@@ -0,0 +1,689 @@
+/*
+ * 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.
+ */
+
+// Controller for Clusters screen.
+export default ['clustersController', [
+    '$rootScope', '$scope', '$http', '$state', '$timeout', 'IgniteLegacyUtils', 'IgniteMessages', 'IgniteConfirm', 'IgniteClone', 'IgniteLoading', 'IgniteModelNormalizer', 'IgniteUnsavedChangesGuard', 'igniteEventGroups', 'DemoInfo', 'IgniteLegacyTable', 'igniteConfigurationResource', 'IgniteErrorPopover', 'IgniteFormUtils',
+    function($root, $scope, $http, $state, $timeout, LegacyUtils, Messages, Confirm, Clone, Loading, ModelNormalizer, UnsavedChangesGuard, igniteEventGroups, DemoInfo, LegacyTable, Resource, ErrorPopover, FormUtils) {
+        UnsavedChangesGuard.install($scope);
+
+        const emptyCluster = {empty: true};
+
+        let __original_value;
+
+        const blank = {
+            atomicConfiguration: {},
+            binaryConfiguration: {},
+            cacheKeyConfiguration: [],
+            communication: {},
+            connector: {},
+            discovery: {
+                Cloud: {
+                    regions: [],
+                    zones: []
+                }
+            },
+            marshaller: {},
+            sslContextFactory: {
+                trustManagers: []
+            },
+            swapSpaceSpi: {},
+            transactionConfiguration: {},
+            collision: {}
+        };
+
+        const pairFields = {
+            attributes: {id: 'Attribute', idPrefix: 'Key', searchCol: 'name', valueCol: 'key', dupObjName: 'name', group: 'attributes'},
+            'collision.JobStealing.stealingAttributes': {id: 'CAttribute', idPrefix: 'Key', searchCol: 'name', valueCol: 'key', dupObjName: 'name', group: 'collision'}
+        };
+
+        $scope.tablePairValid = function(item, field, index, stopEdit) {
+            const pairField = pairFields[field.model];
+
+            const pairValue = LegacyTable.tablePairValue(field, index);
+
+            if (pairField) {
+                const model = _.get(item, field.model);
+
+                if (LegacyUtils.isDefined(model)) {
+                    const idx = _.findIndex(model, (pair) => {
+                        return pair[pairField.searchCol] === pairValue[pairField.valueCol];
+                    });
+
+                    // Found duplicate by key.
+                    if (idx >= 0 && idx !== index) {
+                        if (stopEdit)
+                            return false;
+
+                        return ErrorPopover.show(LegacyTable.tableFieldId(index, pairField.idPrefix + pairField.id), 'Attribute with such ' + pairField.dupObjName + ' already exists!', $scope.ui, pairField.group);
+                    }
+                }
+            }
+
+            return true;
+        };
+
+        $scope.tableSave = function(field, index, stopEdit) {
+            if (LegacyTable.tablePairSaveVisible(field, index))
+                return LegacyTable.tablePairSave($scope.tablePairValid, $scope.backupItem, field, index, stopEdit);
+
+            return true;
+        };
+
+        $scope.tableReset = (trySave) => {
+            const field = LegacyTable.tableField();
+
+            if (trySave && LegacyUtils.isDefined(field) && !$scope.tableSave(field, LegacyTable.tableEditedRowIndex(), true))
+                return false;
+
+            LegacyTable.tableReset();
+
+            return true;
+        };
+
+        $scope.tableNewItem = function(field) {
+            if ($scope.tableReset(true)) {
+                if (field.type === 'failoverSpi') {
+                    if (LegacyUtils.isDefined($scope.backupItem.failoverSpi))
+                        $scope.backupItem.failoverSpi.push({});
+                    else
+                        $scope.backupItem.failoverSpi = {};
+                }
+                else
+                    LegacyTable.tableNewItem(field);
+            }
+        };
+
+        $scope.tableNewItemActive = LegacyTable.tableNewItemActive;
+
+        $scope.tableStartEdit = function(item, field, index) {
+            if ($scope.tableReset(true))
+                LegacyTable.tableStartEdit(item, field, index, $scope.tableSave);
+        };
+
+        $scope.tableEditing = LegacyTable.tableEditing;
+
+        $scope.tableRemove = function(item, field, index) {
+            if ($scope.tableReset(true))
+                LegacyTable.tableRemove(item, field, index);
+        };
+
+        $scope.tablePairSave = LegacyTable.tablePairSave;
+        $scope.tablePairSaveVisible = LegacyTable.tablePairSaveVisible;
+
+        $scope.attributesTbl = {
+            type: 'attributes',
+            model: 'attributes',
+            focusId: 'Attribute',
+            ui: 'table-pair',
+            keyName: 'name',
+            valueName: 'value',
+            save: $scope.tableSave
+        };
+
+        $scope.stealingAttributesTbl = {
+            type: 'attributes',
+            model: 'collision.JobStealing.stealingAttributes',
+            focusId: 'CAttribute',
+            ui: 'table-pair',
+            keyName: 'name',
+            valueName: 'value',
+            save: $scope.tableSave
+        };
+
+        $scope.removeFailoverConfiguration = function(idx) {
+            $scope.backupItem.failoverSpi.splice(idx, 1);
+        };
+
+        // We need to initialize backupItem with empty object in order to properly used from angular directives.
+        $scope.backupItem = emptyCluster;
+
+        $scope.ui = FormUtils.formUI();
+        $scope.ui.activePanels = [0];
+        $scope.ui.topPanels = [0];
+
+        $scope.saveBtnTipText = FormUtils.saveBtnTipText;
+        $scope.widthIsSufficient = FormUtils.widthIsSufficient;
+
+        $scope.contentVisible = function() {
+            const item = $scope.backupItem;
+
+            return !item.empty && (!item._id || _.find($scope.displayedRows, {_id: item._id}));
+        };
+
+        $scope.toggleExpanded = function() {
+            $scope.ui.expanded = !$scope.ui.expanded;
+
+            ErrorPopover.hide();
+        };
+
+        $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'},
+            {value: 'ZooKeeper', label: 'Apache ZooKeeper'}
+        ];
+
+        $scope.swapSpaceSpis = [
+            {value: 'FileSwapSpaceSpi', label: 'File-based swap'},
+            {value: null, label: 'Not set'}
+        ];
+
+        $scope.eventGroups = igniteEventGroups;
+
+        $scope.clusters = [];
+
+        function _clusterLbl(cluster) {
+            return cluster.name + ', ' + _.find($scope.discoveries, {value: cluster.discovery.kind}).label;
+        }
+
+        function selectFirstItem() {
+            if ($scope.clusters.length > 0)
+                $scope.selectItem($scope.clusters[0]);
+        }
+
+        Loading.start('loadingClustersScreen');
+
+        // When landing on the page, get clusters and show them.
+        Resource.read()
+            .then(({spaces, clusters, caches, igfss}) => {
+                $scope.spaces = spaces;
+                $scope.clusters = clusters;
+
+                $scope.caches = _.map(caches, (cache) => ({value: cache._id, label: cache.name, cache}));
+                $scope.igfss = _.map(igfss, (igfs) => ({value: igfs._id, label: igfs.name, igfs}));
+
+                _.forEach($scope.clusters, (cluster) => {
+                    cluster.label = _clusterLbl(cluster);
+
+                    if (!cluster.collision || !cluster.collision.kind)
+                        cluster.collision = {kind: 'Noop', JobStealing: {stealingEnabled: true}, PriorityQueue: {starvationPreventionEnabled: true}};
+
+                    if (!cluster.failoverSpi)
+                        cluster.failoverSpi = [];
+
+                    if (!cluster.logger)
+                        cluster.logger = {Log4j: { mode: 'Default'}};
+                });
+
+                if ($state.params.linkId)
+                    $scope.createItem($state.params.linkId);
+                else {
+                    const lastSelectedCluster = angular.fromJson(sessionStorage.lastSelectedCluster);
+
+                    if (lastSelectedCluster) {
+                        const idx = _.findIndex($scope.clusters, (cluster) => cluster._id === lastSelectedCluster);
+
+                        if (idx >= 0)
+                            $scope.selectItem($scope.clusters[idx]);
+                        else {
+                            sessionStorage.removeItem('lastSelectedCluster');
+
+                            selectFirstItem();
+                        }
+                    }
+                    else
+                        selectFirstItem();
+                }
+
+                $scope.$watch('ui.inputForm.$valid', function(valid) {
+                    if (valid && ModelNormalizer.isEqual(__original_value, $scope.backupItem))
+                        $scope.ui.inputForm.$dirty = false;
+                });
+
+                $scope.$watch('backupItem', function(val) {
+                    if (!$scope.ui.inputForm)
+                        return;
+
+                    const form = $scope.ui.inputForm;
+
+                    if (form.$valid && ModelNormalizer.isEqual(__original_value, val))
+                        form.$setPristine();
+                    else
+                        form.$setDirty();
+                }, true);
+
+                $scope.$watch('ui.activePanels.length', () => {
+                    ErrorPopover.hide();
+                });
+
+                if ($root.IgniteDemoMode && sessionStorage.showDemoInfo !== 'true') {
+                    sessionStorage.showDemoInfo = 'true';
+
+                    DemoInfo.show();
+                }
+            })
+            .catch(Messages.showError)
+            .then(() => {
+                $scope.ui.ready = true;
+                $scope.ui.inputForm && $scope.ui.inputForm.$setPristine();
+
+                Loading.finish('loadingClustersScreen');
+            });
+
+        $scope.selectItem = function(item, backup) {
+            function selectItem() {
+                $scope.selectedItem = item;
+
+                try {
+                    if (item && item._id)
+                        sessionStorage.lastSelectedCluster = angular.toJson(item._id);
+                    else
+                        sessionStorage.removeItem('lastSelectedCluster');
+                }
+                catch (ignored) {
+                    // No-op.
+                }
+
+                if (backup)
+                    $scope.backupItem = backup;
+                else if (item)
+                    $scope.backupItem = angular.copy(item);
+                else
+                    $scope.backupItem = emptyCluster;
+
+                $scope.backupItem = angular.merge({}, blank, $scope.backupItem);
+
+                if ($scope.ui.inputForm) {
+                    $scope.ui.inputForm.$error = {};
+                    $scope.ui.inputForm.$setPristine();
+                }
+
+                __original_value = ModelNormalizer.normalize($scope.backupItem);
+
+                if (LegacyUtils.getQueryVariable('new'))
+                    $state.go('base.configuration.clusters');
+            }
+
+            FormUtils.confirmUnsavedChanges($scope.backupItem && $scope.ui.inputForm && $scope.ui.inputForm.$dirty, selectItem);
+        };
+
+        $scope.linkId = () => $scope.backupItem._id ? $scope.backupItem._id : 'create';
+
+        function prepareNewItem(linkId) {
+            return angular.merge({}, blank, {
+                space: $scope.spaces[0]._id,
+                discovery: {
+                    kind: 'Multicast',
+                    Vm: {addresses: ['127.0.0.1:47500..47510']},
+                    Multicast: {addresses: ['127.0.0.1:47500..47510']},
+                    Jdbc: {initSchema: true}
+                },
+                binaryConfiguration: {typeConfigurations: [], compactFooter: true},
+                communication: {tcpNoDelay: true},
+                connector: {noDelay: true},
+                collision: {kind: 'Noop', JobStealing: {stealingEnabled: true}, PriorityQueue: {starvationPreventionEnabled: true}},
+                failoverSpi: [],
+                logger: {Log4j: { mode: 'Default'}},
+                caches: linkId && _.find($scope.caches, {value: linkId}) ? [linkId] : [],
+                igfss: linkId && _.find($scope.igfss, {value: linkId}) ? [linkId] : []
+            });
+        }
+
+        // Add new cluster.
+        $scope.createItem = function(linkId) {
+            $timeout(() => FormUtils.ensureActivePanel($scope.ui, 'general', 'clusterNameInput'));
+
+            $scope.selectItem(null, prepareNewItem(linkId));
+        };
+
+        $scope.indexOfCache = function(cacheId) {
+            return _.findIndex($scope.caches, (cache) => cache.value === cacheId);
+        };
+
+        function clusterCaches(item) {
+            return _.filter(_.map($scope.caches, (scopeCache) => scopeCache.cache),
+                (cache) => _.includes(item.caches, cache._id));
+        }
+
+        function checkCacheDatasources(item) {
+            const caches = clusterCaches(item);
+
+            const checkRes = LegacyUtils.checkDataSources(item, caches);
+
+            if (!checkRes.checked) {
+                if (_.get(checkRes.secondObj, 'discovery.kind') === 'Jdbc') {
+                    return ErrorPopover.show('dialectInput',
+                        'Found cache "' + checkRes.firstObj.name + '" with the same data source bean name "' +
+                        item.discovery.Jdbc.dataSourceBean + '" and different database: "' +
+                        LegacyUtils.cacheStoreJdbcDialectsLabel(checkRes.secondDB) + '" in current cluster and "' +
+                        LegacyUtils.cacheStoreJdbcDialectsLabel(checkRes.firstDB) + '" in "' + checkRes.firstObj.name + '" cache',
+                        $scope.ui, 'general', 10000);
+                }
+
+                return ErrorPopover.show('cachesInput',
+                    'Found caches "' + checkRes.firstObj.name + '" and "' + checkRes.secondObj.name + '" ' +
+                    'with the same data source bean name "' + checkRes.firstObj.cacheStoreFactory[checkRes.firstObj.cacheStoreFactory.kind].dataSourceBean +
+                    '" and different databases: "' + LegacyUtils.cacheStoreJdbcDialectsLabel(checkRes.firstDB) + '" in "' + checkRes.firstObj.name + '" and "' +
+                    LegacyUtils.cacheStoreJdbcDialectsLabel(checkRes.secondDB) + '" in "' + checkRes.secondObj.name + '" cache',
+                    $scope.ui, 'general', 10000);
+            }
+
+            return true;
+        }
+
+        function checkCacheSQLSchemas(item) {
+            const caches = clusterCaches(item);
+
+            const checkRes = LegacyUtils.checkCacheSQLSchemas(caches);
+
+            if (!checkRes.checked) {
+                return ErrorPopover.show('cachesInput',
+                    'Found caches "' + checkRes.firstCache.name + '" and "' + checkRes.secondCache.name + '" ' +
+                    'with the same SQL schema name "' + checkRes.firstCache.sqlSchema + '"',
+                    $scope.ui, 'general', 10000);
+            }
+
+            return true;
+        }
+
+        function checkBinaryConfiguration(item) {
+            const b = item.binaryConfiguration;
+
+            if (LegacyUtils.isDefined(b)) {
+                if (!_.isEmpty(b.typeConfigurations)) {
+                    for (let typeIx = 0; typeIx < b.typeConfigurations.length; typeIx++) {
+                        const type = b.typeConfigurations[typeIx];
+
+                        if (LegacyUtils.isEmptyString(type.typeName))
+                            return ErrorPopover.show('typeName' + typeIx + 'Input', 'Type name should be specified!', $scope.ui, 'binary');
+
+                        if (_.find(b.typeConfigurations, (t, ix) => ix < typeIx && t.typeName === type.typeName))
+                            return ErrorPopover.show('typeName' + typeIx + 'Input', 'Type with such name is already specified!', $scope.ui, 'binary');
+                    }
+                }
+            }
+
+            return true;
+        }
+
+        function checkCacheKeyConfiguration(item) {
+            const cfgs = item.cacheKeyConfiguration;
+
+            if (_.isEmpty(cfgs))
+                return true;
+
+            for (let typeIx = 0; typeIx < cfgs.length; typeIx++) {
+                const type = cfgs[typeIx];
+
+                if (LegacyUtils.isEmptyString(type.typeName))
+                    return ErrorPopover.show('cacheKeyTypeName' + typeIx + 'Input', 'Cache type configuration name should be specified!', $scope.ui, 'cacheKeyCfg');
+
+                if (_.find(cfgs, (t, ix) => ix < typeIx && t.typeName === type.typeName))
+                    return ErrorPopover.show('cacheKeyTypeName' + typeIx + 'Input', 'Cache type configuration with such name is already specified!', $scope.ui, 'cacheKeyCfg');
+            }
+
+            return true;
+        }
+
+        function checkCommunicationConfiguration(item) {
+            const c = item.communication;
+
+            if (LegacyUtils.isDefined(c)) {
+                if (LegacyUtils.isDefined(c.unacknowledgedMessagesBufferSize)) {
+                    if (LegacyUtils.isDefined(c.messageQueueLimit) && c.unacknowledgedMessagesBufferSize < 5 * c.messageQueueLimit)
+                        return ErrorPopover.show('unacknowledgedMessagesBufferSizeInput', 'Maximum number of stored unacknowledged messages should be at least 5 * message queue limit!', $scope.ui, 'communication');
+
+                    if (LegacyUtils.isDefined(c.ackSendThreshold) && c.unacknowledgedMessagesBufferSize < 5 * c.ackSendThreshold)
+                        return ErrorPopover.show('unacknowledgedMessagesBufferSizeInput', 'Maximum number of stored unacknowledged messages should be at least 5 * ack send threshold!', $scope.ui, 'communication');
+                }
+
+                if (c.sharedMemoryPort === 0)
+                    return ErrorPopover.show('sharedMemoryPortInput', 'Shared memory port should be more than "0" or equals to "-1"!', $scope.ui, 'communication');
+            }
+
+            return true;
+        }
+
+        function checkDiscoveryConfiguration(item) {
+            const d = item.discovery;
+
+            if (d) {
+                if ((_.isNil(d.maxAckTimeout) ? 600000 : d.maxAckTimeout) < (d.ackTimeout || 5000))
+                    return ErrorPopover.show('ackTimeoutInput', 'Acknowledgement timeout should be less than max acknowledgement timeout!', $scope.ui, 'discovery');
+
+                if (d.kind === 'Vm' && d.Vm && d.Vm.addresses.length === 0)
+                    return ErrorPopover.show('addresses', 'Addresses are not specified!', $scope.ui, 'general');
+            }
+
+            return true;
+        }
+
+        function checkSwapConfiguration(item) {
+            const swapKind = item.swapSpaceSpi && item.swapSpaceSpi.kind;
+
+            if (swapKind && item.swapSpaceSpi[swapKind]) {
+                const swap = item.swapSpaceSpi[swapKind];
+
+                const sparsity = swap.maximumSparsity;
+
+                if (LegacyUtils.isDefined(sparsity) && (sparsity < 0 || sparsity >= 1))
+                    return ErrorPopover.show('maximumSparsityInput', 'Maximum sparsity should be more or equal 0 and less than 1!', $scope.ui, 'swap');
+
+                const readStripesNumber = swap.readStripesNumber;
+
+                if (readStripesNumber && !(readStripesNumber === -1 || (readStripesNumber & (readStripesNumber - 1)) === 0))
+                    return ErrorPopover.show('readStripesNumberInput', 'Read stripe size must be positive and power of two!', $scope.ui, 'swap');
+            }
+
+            return true;
+        }
+
+        function checkSslConfiguration(item) {
+            const r = item.connector;
+
+            if (LegacyUtils.isDefined(r)) {
+                if (r.sslEnabled && LegacyUtils.isEmptyString(r.sslFactory))
+                    return ErrorPopover.show('connectorSslFactoryInput', 'SSL factory should not be empty!', $scope.ui, 'connector');
+            }
+
+            if (item.sslEnabled) {
+                if (!LegacyUtils.isDefined(item.sslContextFactory) || LegacyUtils.isEmptyString(item.sslContextFactory.keyStoreFilePath))
+                    return ErrorPopover.show('keyStoreFilePathInput', 'Key store file should not be empty!', $scope.ui, 'sslConfiguration');
+
+                if (LegacyUtils.isEmptyString(item.sslContextFactory.trustStoreFilePath) && _.isEmpty(item.sslContextFactory.trustManagers))
+                    return ErrorPopover.show('sslConfiguration-title', 'Trust storage file or managers should be configured!', $scope.ui, 'sslConfiguration');
+            }
+
+            return true;
+        }
+
+        function checkPoolSizes(item) {
+            if (item.rebalanceThreadPoolSize && item.systemThreadPoolSize && item.systemThreadPoolSize <= item.rebalanceThreadPoolSize)
+                return ErrorPopover.show('rebalanceThreadPoolSizeInput', 'Rebalance thread pool size exceed or equals System thread pool size!', $scope.ui, 'pools');
+
+            return true;
+        }
+
+        // Check cluster logical consistency.
+        function validate(item) {
+            ErrorPopover.hide();
+
+            if (LegacyUtils.isEmptyString(item.name))
+                return ErrorPopover.show('clusterNameInput', 'Cluster name should not be empty!', $scope.ui, 'general');
+
+            if (!LegacyUtils.checkFieldValidators($scope.ui))
+                return false;
+
+            if (!checkCacheSQLSchemas(item))
+                return false;
+
+            if (!checkCacheDatasources(item))
+                return false;
+
+            if (!checkBinaryConfiguration(item))
+                return false;
+
+            if (!checkCacheKeyConfiguration(item))
+                return false;
+
+            if (!checkCommunicationConfiguration(item))
+                return false;
+
+            if (!checkDiscoveryConfiguration(item))
+                return false;
+
+            if (!checkSwapConfiguration(item))
+                return false;
+
+            if (!checkSslConfiguration(item))
+                return false;
+
+            if (!checkPoolSizes(item))
+                return false;
+
+            return true;
+        }
+
+        // Save cluster in database.
+        function save(item) {
+            $http.post('/api/v1/configuration/clusters/save', item)
+                .success(function(_id) {
+                    item.label = _clusterLbl(item);
+
+                    $scope.ui.inputForm.$setPristine();
+
+                    const idx = _.findIndex($scope.clusters, (cluster) => cluster._id === _id);
+
+                    if (idx >= 0)
+                        angular.merge($scope.clusters[idx], item);
+                    else {
+                        item._id = _id;
+                        $scope.clusters.push(item);
+                    }
+
+                    _.forEach($scope.caches, (cache) => {
+                        if (_.includes(item.caches, cache.value))
+                            cache.cache.clusters = _.union(cache.cache.clusters, [_id]);
+                        else
+                            _.remove(cache.cache.clusters, (id) => id === _id);
+                    });
+
+                    _.forEach($scope.igfss, (igfs) => {
+                        if (_.includes(item.igfss, igfs.value))
+                            igfs.igfs.clusters = _.union(igfs.igfs.clusters, [_id]);
+                        else
+                            _.remove(igfs.igfs.clusters, (id) => id === _id);
+                    });
+
+                    $scope.selectItem(item);
+
+                    Messages.showInfo('Cluster "' + item.name + '" saved.');
+                })
+                .error(Messages.showError);
+        }
+
+        // Save cluster.
+        $scope.saveItem = function() {
+            const item = $scope.backupItem;
+
+            const swapSpi = LegacyUtils.autoClusterSwapSpiConfiguration(item, clusterCaches(item));
+
+            if (swapSpi)
+                angular.extend(item, swapSpi);
+
+            if (validate(item))
+                save(item);
+        };
+
+        function _clusterNames() {
+            return _.map($scope.clusters, (cluster) => cluster.name);
+        }
+
+        // Clone cluster with new name.
+        $scope.cloneItem = function() {
+            if (validate($scope.backupItem)) {
+                Clone.confirm($scope.backupItem.name, _clusterNames()).then(function(newName) {
+                    const item = angular.copy($scope.backupItem);
+
+                    delete item._id;
+                    item.name = newName;
+
+                    save(item);
+                });
+            }
+        };
+
+        // Remove cluster from db.
+        $scope.removeItem = function() {
+            const selectedItem = $scope.selectedItem;
+
+            Confirm.confirm('Are you sure you want to remove cluster: "' + selectedItem.name + '"?')
+                .then(function() {
+                    const _id = selectedItem._id;
+
+                    $http.post('/api/v1/configuration/clusters/remove', {_id})
+                        .success(function() {
+                            Messages.showInfo('Cluster has been removed: ' + selectedItem.name);
+
+                            const clusters = $scope.clusters;
+
+                            const idx = _.findIndex(clusters, (cluster) => cluster._id === _id);
+
+                            if (idx >= 0) {
+                                clusters.splice(idx, 1);
+
+                                $scope.ui.inputForm.$setPristine();
+
+                                if (clusters.length > 0)
+                                    $scope.selectItem(clusters[0]);
+                                else
+                                    $scope.backupItem = emptyCluster;
+
+                                _.forEach($scope.caches, (cache) => _.remove(cache.cache.clusters, (id) => id === _id));
+                                _.forEach($scope.igfss, (igfs) => _.remove(igfs.igfs.clusters, (id) => id === _id));
+                            }
+                        })
+                        .error(Messages.showError);
+                });
+        };
+
+        // Remove all clusters from db.
+        $scope.removeAllItems = function() {
+            Confirm.confirm('Are you sure you want to remove all clusters?')
+                .then(function() {
+                    $http.post('/api/v1/configuration/clusters/remove/all')
+                        .success(() => {
+                            Messages.showInfo('All clusters have been removed');
+
+                            $scope.clusters = [];
+
+                            _.forEach($scope.caches, (cache) => cache.cache.clusters = []);
+                            _.forEach($scope.igfss, (igfs) => igfs.igfs.clusters = []);
+
+                            $scope.backupItem = emptyCluster;
+                            $scope.ui.inputForm.$error = {};
+                            $scope.ui.inputForm.$setPristine();
+                        })
+                        .error(Messages.showError);
+                });
+        };
+
+        $scope.resetAll = function() {
+            Confirm.confirm('Are you sure you want to undo all changes for current cluster?')
+                .then(function() {
+                    $scope.backupItem = $scope.selectedItem ? angular.copy($scope.selectedItem) : prepareNewItem();
+                    $scope.ui.inputForm.$error = {};
+                    $scope.ui.inputForm.$setPristine();
+                });
+        };
+    }
+]];


[42/52] ignite git commit: Web Console beta-3.

Posted by ak...@apache.org.
http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/backend/services/clusters.js
----------------------------------------------------------------------
diff --git a/modules/web-console/backend/services/clusters.js b/modules/web-console/backend/services/clusters.js
new file mode 100644
index 0000000..6c2722b
--- /dev/null
+++ b/modules/web-console/backend/services/clusters.js
@@ -0,0 +1,141 @@
+/*
+ * 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.
+ */
+
+'use strict';
+
+// Fire me up!
+
+module.exports = {
+    implements: 'services/clusters',
+    inject: ['require(lodash)', 'mongo', 'services/spaces', 'errors']
+};
+
+/**
+ * @param _
+ * @param mongo
+ * @param {SpacesService} spacesService
+ * @param errors
+ * @returns {ClustersService}
+ */
+module.exports.factory = (_, mongo, spacesService, errors) => {
+    /**
+     * Convert remove status operation to own presentation.
+     * @param {RemoveResult} result - The results of remove operation.
+     */
+    const convertRemoveStatus = ({result}) => ({rowsAffected: result.n});
+
+    /**
+     * Update existing cluster
+     * @param {Object} cluster - The cluster for updating
+     * @returns {Promise.<mongo.ObjectId>} that resolves cluster id
+     */
+    const update = (cluster) => {
+        const clusterId = cluster._id;
+
+        return mongo.Cluster.update({_id: clusterId}, cluster, {upsert: true}).exec()
+            .then(() => mongo.Cache.update({_id: {$in: cluster.caches}}, {$addToSet: {clusters: clusterId}}, {multi: true}).exec())
+            .then(() => mongo.Cache.update({_id: {$nin: cluster.caches}}, {$pull: {clusters: clusterId}}, {multi: true}).exec())
+            .then(() => mongo.Igfs.update({_id: {$in: cluster.igfss}}, {$addToSet: {clusters: clusterId}}, {multi: true}).exec())
+            .then(() => mongo.Igfs.update({_id: {$nin: cluster.igfss}}, {$pull: {clusters: clusterId}}, {multi: true}).exec())
+            .then(() => cluster)
+            .catch((err) => {
+                if (err.code === mongo.errCodes.DUPLICATE_KEY_UPDATE_ERROR || err.code === mongo.errCodes.DUPLICATE_KEY_ERROR)
+                    throw new errors.DuplicateKeyException('Cluster with name: "' + cluster.name + '" already exist.');
+            });
+    };
+
+    /**
+     * Create new cluster.
+     * @param {Object} cluster - The cluster for creation.
+     * @returns {Promise.<mongo.ObjectId>} that resolves cluster id.
+     */
+    const create = (cluster) => {
+        return mongo.Cluster.create(cluster)
+            .then((savedCluster) =>
+                mongo.Cache.update({_id: {$in: savedCluster.caches}}, {$addToSet: {clusters: savedCluster._id}}, {multi: true}).exec()
+                    .then(() => mongo.Igfs.update({_id: {$in: savedCluster.igfss}}, {$addToSet: {clusters: savedCluster._id}}, {multi: true}).exec())
+                    .then(() => savedCluster)
+            )
+            .catch((err) => {
+                if (err.code === mongo.errCodes.DUPLICATE_KEY_ERROR)
+                    throw new errors.DuplicateKeyException('Cluster with name: "' + cluster.name + '" already exist.');
+            });
+    };
+
+    /**
+     * Remove all caches by space ids.
+     * @param {Number[]} spaceIds - The space ids for cache deletion.
+     * @returns {Promise.<RemoveResult>} - that resolves results of remove operation.
+     */
+    const removeAllBySpaces = (spaceIds) => {
+        return mongo.Cache.update({space: {$in: spaceIds}}, {clusters: []}, {multi: true}).exec()
+            .then(() => mongo.Igfs.update({space: {$in: spaceIds}}, {clusters: []}, {multi: true}).exec())
+            .then(() => mongo.Cluster.remove({space: {$in: spaceIds}}).exec());
+    };
+
+    class ClustersService {
+        /**
+         * Create or update cluster.
+         * @param {Object} cluster - The cluster
+         * @returns {Promise.<mongo.ObjectId>} that resolves cluster id of merge operation.
+         */
+        static merge(cluster) {
+            if (cluster._id)
+                return update(cluster);
+
+            return create(cluster);
+        }
+
+        /**
+         * Get clusters and linked objects by space.
+         * @param {mongo.ObjectId|String} spaceIds - The spaces id that own cluster.
+         * @returns {Promise.<[mongo.Cache[], mongo.Cluster[], mongo.DomainModel[], mongo.Space[]]>} - contains requested caches and array of linked objects: clusters, domains, spaces.
+         */
+        static listBySpaces(spaceIds) {
+            return mongo.Cluster.find({space: {$in: spaceIds}}).sort('name').lean().exec();
+        }
+
+        /**
+         * Remove cluster.
+         * @param {mongo.ObjectId|String} clusterId - The cluster id for remove.
+         * @returns {Promise.<{rowsAffected}>} - The number of affected rows.
+         */
+        static remove(clusterId) {
+            if (_.isNil(clusterId))
+                return Promise.reject(new errors.IllegalArgumentException('Cluster id can not be undefined or null'));
+
+            return mongo.Cache.update({clusters: {$in: [clusterId]}}, {$pull: {clusters: clusterId}}, {multi: true}).exec()
+                .then(() => mongo.Igfs.update({clusters: {$in: [clusterId]}}, {$pull: {clusters: clusterId}}, {multi: true}).exec())
+                .then(() => mongo.Cluster.remove({_id: clusterId}).exec())
+                .then(convertRemoveStatus);
+        }
+
+        /**
+         * Remove all clusters by user.
+         * @param {mongo.ObjectId|String} userId - The user id that own cluster.
+         * @param {Boolean} demo - The flag indicates that need lookup in demo space.
+         * @returns {Promise.<{rowsAffected}>} - The number of affected rows.
+         */
+        static removeAll(userId, demo) {
+            return spacesService.spaceIds(userId, demo)
+                .then(removeAllBySpaces)
+                .then(convertRemoveStatus);
+        }
+    }
+
+    return ClustersService;
+};

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/backend/services/configurations.js
----------------------------------------------------------------------
diff --git a/modules/web-console/backend/services/configurations.js b/modules/web-console/backend/services/configurations.js
new file mode 100644
index 0000000..7eef8a2
--- /dev/null
+++ b/modules/web-console/backend/services/configurations.js
@@ -0,0 +1,59 @@
+/*
+ * 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.
+ */
+
+'use strict';
+
+// Fire me up!
+
+module.exports = {
+    implements: 'services/configurations',
+    inject: ['require(lodash)', 'mongo', 'services/spaces', 'services/clusters', 'services/caches', 'services/domains', 'services/igfss']
+};
+
+/**
+ * @param _
+ * @param mongo
+ * @param {SpacesService} spacesService
+ * @param {ClustersService} clustersService
+ * @param {CachesService} cachesService
+ * @param {DomainsService} domainsService
+ * @param {IgfssService} igfssService
+ * @returns {ConfigurationsService}
+ */
+module.exports.factory = (_, mongo, spacesService, clustersService, cachesService, domainsService, igfssService) => {
+    class ConfigurationsService {
+        static list(userId, demo) {
+            let spaces;
+
+            return spacesService.spaces(userId, demo)
+                .then((_spaces) => {
+                    spaces = _spaces;
+
+                    return spaces.map((space) => space._id);
+                })
+                .then((spaceIds) => Promise.all([
+                    clustersService.listBySpaces(spaceIds),
+                    domainsService.listBySpaces(spaceIds),
+                    cachesService.listBySpaces(spaceIds),
+                    igfssService.listBySpaces(spaceIds)
+                ]))
+                .then(([clusters, domains, caches, igfss]) => ({clusters, domains, caches, igfss, spaces}));
+        }
+    }
+
+    return ConfigurationsService;
+};

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/backend/services/domains.js
----------------------------------------------------------------------
diff --git a/modules/web-console/backend/services/domains.js b/modules/web-console/backend/services/domains.js
new file mode 100644
index 0000000..3e4e129
--- /dev/null
+++ b/modules/web-console/backend/services/domains.js
@@ -0,0 +1,187 @@
+/*
+ * 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.
+ */
+
+'use strict';
+
+// Fire me up!
+
+module.exports = {
+    implements: 'services/domains',
+    inject: ['require(lodash)', 'mongo', 'services/spaces', 'services/caches', 'errors']
+};
+
+/**
+ * @param _
+ * @param mongo
+ * @param {SpacesService} spacesService
+ * @param {CachesService} cachesService
+ * @param errors
+ * @returns {DomainsService}
+ */
+module.exports.factory = (_, mongo, spacesService, cachesService, errors) => {
+    /**
+     * Convert remove status operation to own presentation.
+     * @param {RemoveResult} result - The results of remove operation.
+     */
+    const convertRemoveStatus = ({result}) => ({rowsAffected: result.n});
+
+    const _updateCacheStore = (cacheStoreChanges) =>
+        Promise.all(_.map(cacheStoreChanges, (change) => mongo.Cache.update({_id: {$eq: change.cacheId}}, change.change, {}).exec()));
+
+    /**
+     * Update existing domain
+     * @param {Object} domain - The domain for updating
+     * @param savedDomains List of saved domains.
+     * @returns {Promise.<mongo.ObjectId>} that resolves domain id
+     */
+    const update = (domain, savedDomains) => {
+        const domainId = domain._id;
+
+        return mongo.DomainModel.update({_id: domainId}, domain, {upsert: true}).exec()
+            .then(() => mongo.Cache.update({_id: {$in: domain.caches}}, {$addToSet: {domains: domainId}}, {multi: true}).exec())
+            .then(() => mongo.Cache.update({_id: {$nin: domain.caches}}, {$pull: {domains: domainId}}, {multi: true}).exec())
+            .then(() => {
+                savedDomains.push(domain);
+
+                return _updateCacheStore(domain.cacheStoreChanges);
+            })
+            .catch((err) => {
+                if (err.code === mongo.errCodes.DUPLICATE_KEY_UPDATE_ERROR || err.code === mongo.errCodes.DUPLICATE_KEY_ERROR)
+                    throw new errors.DuplicateKeyException('Domain model with value type: "' + domain.valueType + '" already exist.');
+            });
+    };
+
+    /**
+     * Create new domain.
+     * @param {Object} domain - The domain for creation.
+     * @param savedDomains List of saved domains.
+     * @returns {Promise.<mongo.ObjectId>} that resolves cluster id.
+     */
+    const create = (domain, savedDomains) => {
+        return mongo.DomainModel.create(domain)
+            .then((createdDomain) => {
+                savedDomains.push(createdDomain);
+
+                return mongo.Cache.update({_id: {$in: domain.caches}}, {$addToSet: {domains: createdDomain._id}}, {multi: true}).exec()
+                    .then(() => _updateCacheStore(domain.cacheStoreChanges));
+            })
+            .catch((err) => {
+                if (err.code === mongo.errCodes.DUPLICATE_KEY_ERROR)
+                    throw new errors.DuplicateKeyException('Domain model with value type: "' + domain.valueType + '" already exist.');
+            });
+    };
+
+    const _saveDomainModel = (domain, savedDomains) => {
+        const domainId = domain._id;
+
+        if (domainId)
+            return update(domain, savedDomains);
+
+        return create(domain, savedDomains);
+    };
+
+    const _save = (domains) => {
+        if (_.isEmpty(domains))
+            throw new errors.IllegalArgumentException('Nothing to save!');
+
+        const savedDomains = [];
+        const generatedCaches = [];
+
+        const promises = _.map(domains, (domain) => {
+            if (domain.newCache) {
+                return mongo.Cache.findOne({space: domain.space, name: domain.newCache.name}).exec()
+                    .then((cache) => {
+                        if (cache)
+                            return Promise.resolve(cache);
+
+                        // If cache not found, then create it and associate with domain model.
+                        const newCache = domain.newCache;
+                        newCache.space = domain.space;
+
+                        return cachesService.merge(newCache);
+                    })
+                    .then((cache) => {
+                        domain.caches = [cache._id];
+
+                        return _saveDomainModel(domain, savedDomains);
+                    });
+            }
+
+            return _saveDomainModel(domain, savedDomains);
+        });
+
+        return Promise.all(promises).then(() => ({savedDomains, generatedCaches}));
+    };
+
+    /**
+     * Remove all caches by space ids.
+     * @param {Array.<Number>} spaceIds - The space ids for cache deletion.
+     * @returns {Promise.<RemoveResult>} - that resolves results of remove operation.
+     */
+    const removeAllBySpaces = (spaceIds) => {
+        return mongo.Cache.update({space: {$in: spaceIds}}, {domains: []}, {multi: true}).exec()
+            .then(() => mongo.DomainModel.remove({space: {$in: spaceIds}}).exec());
+    };
+
+    class DomainsService {
+        /**
+         * Batch merging domains.
+         * @param {Array.<mongo.DomainModel>} domains
+         */
+        static batchMerge(domains) {
+            return _save(domains);
+        }
+
+        /**
+         * Get domain and linked objects by space.
+         * @param {mongo.ObjectId|String} spaceIds - The space id that own domain.
+         * @returns {Promise.<[mongo.Cache[], mongo.Cluster[], mongo.DomainModel[], mongo.Space[]]>}
+         *      contains requested domains and array of linked objects: caches, spaces.
+         */
+        static listBySpaces(spaceIds) {
+            return mongo.DomainModel.find({space: {$in: spaceIds}}).sort('valueType').lean().exec();
+        }
+
+        /**
+         * Remove domain.
+         * @param {mongo.ObjectId|String} domainId - The domain id for remove.
+         * @returns {Promise.<{rowsAffected}>} - The number of affected rows.
+         */
+        static remove(domainId) {
+            if (_.isNil(domainId))
+                return Promise.reject(new errors.IllegalArgumentException('Domain id can not be undefined or null'));
+
+            return mongo.Cache.update({domains: {$in: [domainId]}}, {$pull: {domains: domainId}}, {multi: true}).exec()
+                .then(() => mongo.DomainModel.remove({_id: domainId}).exec())
+                .then(convertRemoveStatus);
+        }
+
+        /**
+         * Remove all domains by user.
+         * @param {mongo.ObjectId|String} userId - The user id that own domain.
+         * @param {Boolean} demo - The flag indicates that need lookup in demo space.
+         * @returns {Promise.<{rowsAffected}>} - The number of affected rows.
+         */
+        static removeAll(userId, demo) {
+            return spacesService.spaceIds(userId, demo)
+                .then(removeAllBySpaces)
+                .then(convertRemoveStatus);
+        }
+    }
+
+    return DomainsService;
+};

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/backend/services/igfss.js
----------------------------------------------------------------------
diff --git a/modules/web-console/backend/services/igfss.js b/modules/web-console/backend/services/igfss.js
new file mode 100644
index 0000000..20f0121
--- /dev/null
+++ b/modules/web-console/backend/services/igfss.js
@@ -0,0 +1,136 @@
+/*
+ * 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.
+ */
+
+'use strict';
+
+// Fire me up!
+
+module.exports = {
+    implements: 'services/igfss',
+    inject: ['require(lodash)', 'mongo', 'services/spaces', 'errors']
+};
+
+/**
+ * @param _
+ * @param mongo
+ * @param {SpacesService} spacesService
+ * @param errors
+ * @returns {IgfssService}
+ */
+module.exports.factory = (_, mongo, spacesService, errors) => {
+    /**
+     * Convert remove status operation to own presentation.
+     * @param {RemoveResult} result - The results of remove operation.
+     */
+    const convertRemoveStatus = ({result}) => ({rowsAffected: result.n});
+
+    /**
+     * Update existing IGFS
+     * @param {Object} igfs - The IGFS for updating
+     * @returns {Promise.<mongo.ObjectId>} that resolves IGFS id
+     */
+    const update = (igfs) => {
+        const igfsId = igfs._id;
+
+        return mongo.Igfs.update({_id: igfsId}, igfs, {upsert: true}).exec()
+            .then(() => mongo.Cluster.update({_id: {$in: igfs.clusters}}, {$addToSet: {igfss: igfsId}}, {multi: true}).exec())
+            .then(() => mongo.Cluster.update({_id: {$nin: igfs.clusters}}, {$pull: {igfss: igfsId}}, {multi: true}).exec())
+            .then(() => igfs)
+            .catch((err) => {
+                if (err.code === mongo.errCodes.DUPLICATE_KEY_UPDATE_ERROR || err.code === mongo.errCodes.DUPLICATE_KEY_ERROR)
+                    throw new errors.DuplicateKeyException('IGFS with name: "' + igfs.name + '" already exist.');
+            });
+    };
+
+    /**
+     * Create new IGFS.
+     * @param {Object} igfs - The IGFS for creation.
+     * @returns {Promise.<mongo.ObjectId>} that resolves IGFS id.
+     */
+    const create = (igfs) => {
+        return mongo.Igfs.create(igfs)
+            .then((savedIgfs) =>
+                mongo.Cluster.update({_id: {$in: savedIgfs.clusters}}, {$addToSet: {igfss: savedIgfs._id}}, {multi: true}).exec()
+                    .then(() => savedIgfs)
+            )
+            .catch((err) => {
+                if (err.code === mongo.errCodes.DUPLICATE_KEY_ERROR)
+                    throw new errors.DuplicateKeyException('IGFS with name: "' + igfs.name + '" already exist.');
+            });
+    };
+
+    /**
+     * Remove all IGFSs by space ids.
+     * @param {Number[]} spaceIds - The space ids for IGFS deletion.
+     * @returns {Promise.<RemoveResult>} - that resolves results of remove operation.
+     */
+    const removeAllBySpaces = (spaceIds) => {
+        return mongo.Cluster.update({space: {$in: spaceIds}}, {igfss: []}, {multi: true}).exec()
+            .then(() => mongo.Igfs.remove({space: {$in: spaceIds}}).exec());
+    };
+
+    class IgfssService {
+        /**
+         * Create or update IGFS.
+         * @param {Object} igfs - The IGFS
+         * @returns {Promise.<mongo.ObjectId>} that resolves IGFS id of merge operation.
+         */
+        static merge(igfs) {
+            if (igfs._id)
+                return update(igfs);
+
+            return create(igfs);
+        }
+
+        /**
+         * Get IGFS by spaces.
+         * @param {mongo.ObjectId|String} spacesIds - The spaces ids that own IGFSs.
+         * @returns {Promise.<mongo.IGFS[]>} - contains requested IGFSs.
+         */
+        static listBySpaces(spacesIds) {
+            return mongo.Igfs.find({space: {$in: spacesIds}}).sort('name').lean().exec();
+        }
+
+        /**
+         * Remove IGFS.
+         * @param {mongo.ObjectId|String} igfsId - The IGFS id for remove.
+         * @returns {Promise.<{rowsAffected}>} - The number of affected rows.
+         */
+        static remove(igfsId) {
+            if (_.isNil(igfsId))
+                return Promise.reject(new errors.IllegalArgumentException('IGFS id can not be undefined or null'));
+
+            return mongo.Cluster.update({igfss: {$in: [igfsId]}}, {$pull: {igfss: igfsId}}, {multi: true}).exec()
+                .then(() => mongo.Igfs.remove({_id: igfsId}).exec())
+                .then(convertRemoveStatus);
+        }
+
+        /**
+         * Remove all IGFSes by user.
+         * @param {mongo.ObjectId|String} userId - The user id that own IGFS.
+         * @param {Boolean} demo - The flag indicates that need lookup in demo space.
+         * @returns {Promise.<{rowsAffected}>} - The number of affected rows.
+         */
+        static removeAll(userId, demo) {
+            return spacesService.spaceIds(userId, demo)
+                .then(removeAllBySpaces)
+                .then(convertRemoveStatus);
+        }
+    }
+
+    return IgfssService;
+};

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/backend/services/mails.js
----------------------------------------------------------------------
diff --git a/modules/web-console/backend/services/mails.js b/modules/web-console/backend/services/mails.js
new file mode 100644
index 0000000..0700985
--- /dev/null
+++ b/modules/web-console/backend/services/mails.js
@@ -0,0 +1,131 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+'use strict';
+
+// Fire me up!
+
+module.exports = {
+    implements: 'services/mails',
+    inject: ['require(lodash)', 'require(nodemailer)', 'settings']
+};
+
+/**
+ * @param _
+ * @param nodemailer
+ * @param settings
+ * @returns {MailsService}
+ */
+module.exports.factory = (_, nodemailer, settings) => {
+    /**
+     * Send mail to user.
+     *
+     * @param {Account} user
+     * @param {String} subject
+     * @param {String} html
+     * @param {String} sendErr
+     * @throws {Error}
+     * @return {Promise}
+     */
+    const send = (user, subject, html, sendErr) => {
+        return new Promise((resolve, reject) => {
+            const transportConfig = settings.smtp;
+
+            if (_.isEmpty(transportConfig.service) || _.isEmpty(transportConfig.auth.user) || _.isEmpty(transportConfig.auth.pass))
+                throw new Error('Failed to send email. SMTP server is not configured. Please ask webmaster to setup SMTP server!');
+
+            const mailer = nodemailer.createTransport(transportConfig);
+
+            const sign = settings.smtp.sign ? `<br><br>--------------<br>${settings.smtp.sign}<br>` : '';
+
+            const mail = {
+                from: settings.smtp.from,
+                to: settings.smtp.address(`${user.firstName} ${user.lastName}`, user.email),
+                subject,
+                html: html + sign
+            };
+
+            mailer.sendMail(mail, (err) => {
+                if (err)
+                    return reject(sendErr ? new Error(sendErr) : err);
+
+                resolve(user);
+            });
+        });
+    };
+
+    class MailsService {
+        /**
+         * Send email to user for password reset.
+         * @param host
+         * @param user
+         */
+        static emailUserSignUp(host, user) {
+            const resetLink = `${host}/password/reset?token=${user.resetPasswordToken}`;
+
+            return send(user, `Thanks for signing up for ${settings.smtp.greeting}.`,
+                `Hello ${user.firstName} ${user.lastName}!<br><br>` +
+                `You are receiving this email because you have signed up to use <a href="${host}">${settings.smtp.greeting}</a>.<br><br>` +
+                'If you have not done the sign up and do not know what this email is about, please ignore it.<br>' +
+                'You may reset the password by clicking on the following link, or paste this into your browser:<br><br>' +
+                `<a href="${resetLink}">${resetLink}</a>`);
+        }
+
+        /**
+         * Send email to user for password reset.
+         * @param host
+         * @param user
+         */
+        static emailUserResetLink(host, user) {
+            const resetLink = `${host}/password/reset?token=${user.resetPasswordToken}`;
+
+            return send(user, 'Password Reset',
+                `Hello ${user.firstName} ${user.lastName}!<br><br>` +
+                'You are receiving this because you (or someone else) have requested the reset of the password for your account.<br><br>' +
+                'Please click on the following link, or paste this into your browser to complete the process:<br><br>' +
+                `<a href="${resetLink}">${resetLink}</a><br><br>` +
+                'If you did not request this, please ignore this email and your password will remain unchanged.',
+                'Failed to send email with reset link!');
+        }
+
+        /**
+         * Send email to user for password reset.
+         * @param host
+         * @param user
+         */
+        static emailPasswordChanged(host, user) {
+            return send(user, 'Your password has been changed',
+                `Hello ${user.firstName} ${user.lastName}!<br><br>` +
+                `This is a confirmation that the password for your account on <a href="${host}">${settings.smtp.greeting}</a> has just been changed.<br><br>`,
+                'Password was changed, but failed to send confirmation email!');
+        }
+
+        /**
+         * Send email to user when it was deleted.
+         * @param host
+         * @param user
+         */
+        static emailUserDeletion(host, user) {
+            return send(user, 'Your account was removed',
+                `Hello ${user.firstName} ${user.lastName}!<br><br>` +
+                `You are receiving this email because your account for <a href="${host}">${settings.smtp.greeting}</a> was removed.`,
+                'Account was removed, but failed to send email notification to user!');
+        }
+    }
+
+    return MailsService;
+};

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/backend/services/notebooks.js
----------------------------------------------------------------------
diff --git a/modules/web-console/backend/services/notebooks.js b/modules/web-console/backend/services/notebooks.js
new file mode 100644
index 0000000..8846d8e
--- /dev/null
+++ b/modules/web-console/backend/services/notebooks.js
@@ -0,0 +1,104 @@
+/*
+ * 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.
+ */
+
+'use strict';
+
+// Fire me up!
+
+module.exports = {
+    implements: 'services/notebooks',
+    inject: ['require(lodash)', 'mongo', 'services/spaces', 'errors']
+};
+
+/**
+ * @param _
+ * @param mongo
+ * @param {SpacesService} spacesService
+ * @param errors
+ * @returns {NotebooksService}
+ */
+module.exports.factory = (_, mongo, spacesService, errors) => {
+    /**
+     * Convert remove status operation to own presentation.
+     * @param {RemoveResult} result - The results of remove operation.
+     */
+    const convertRemoveStatus = ({result}) => ({rowsAffected: result.n});
+
+    /**
+     * Update existing notebook
+     * @param {Object} notebook - The notebook for updating
+     * @returns {Promise.<mongo.ObjectId>} that resolves cache id
+     */
+    const update = (notebook) => {
+        return mongo.Notebook.findOneAndUpdate({_id: notebook._id}, notebook, {new: true, upsert: true}).exec()
+            .catch((err) => {
+                if (err.code === mongo.errCodes.DUPLICATE_KEY_UPDATE_ERROR || err.code === mongo.errCodes.DUPLICATE_KEY_ERROR)
+                    throw new errors.DuplicateKeyException('Notebook with name: "' + notebook.name + '" already exist.');
+            });
+    };
+
+    /**
+     * Create new notebook.
+     * @param {Object} notebook - The notebook for creation.
+     * @returns {Promise.<mongo.ObjectId>} that resolves cache id.
+     */
+    const create = (notebook) => {
+        return mongo.Notebook.create(notebook)
+            .catch((err) => {
+                if (err.code === mongo.errCodes.DUPLICATE_KEY_ERROR)
+                    throw new errors.DuplicateKeyException('Notebook with name: "' + notebook.name + '" already exist.');
+            });
+    };
+
+    class NotebooksService {
+        /**
+         * Create or update Notebook.
+         * @param {Object} notebook - The Notebook
+         * @returns {Promise.<mongo.ObjectId>} that resolves Notebook id of merge operation.
+         */
+        static merge(notebook) {
+            if (notebook._id)
+                return update(notebook);
+
+            return create(notebook);
+        }
+
+        /**
+         * Get caches by spaces.
+         * @param {mongo.ObjectId|String} spaceIds - The spaces ids that own caches.
+         * @returns {Promise.<mongo.Cache[]>} - contains requested caches.
+         */
+        static listBySpaces(spaceIds) {
+            return mongo.Notebook.find({space: {$in: spaceIds}}).sort('name').lean().exec();
+        }
+
+        /**
+         * Remove Notebook.
+         * @param {mongo.ObjectId|String} notebookId - The Notebook id for remove.
+         * @returns {Promise.<{rowsAffected}>} - The number of affected rows.
+         */
+        static remove(notebookId) {
+            if (_.isNil(notebookId))
+                return Promise.reject(new errors.IllegalArgumentException('Notebook id can not be undefined or null'));
+
+            return mongo.Notebook.remove({_id: notebookId}).exec()
+                .then(convertRemoveStatus);
+        }
+    }
+
+    return NotebooksService;
+};

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/backend/services/sessions.js
----------------------------------------------------------------------
diff --git a/modules/web-console/backend/services/sessions.js b/modules/web-console/backend/services/sessions.js
new file mode 100644
index 0000000..4fa95a3
--- /dev/null
+++ b/modules/web-console/backend/services/sessions.js
@@ -0,0 +1,63 @@
+/*
+ * 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.
+ */
+
+'use strict';
+
+// Fire me up!
+
+module.exports = {
+    implements: 'services/sessions',
+    inject: ['require(lodash)', 'mongo', 'errors']
+};
+
+/**
+ * @param _
+ * @param mongo
+ * @param errors
+ * @returns {SessionsService}
+ */
+module.exports.factory = (_, mongo, errors) => {
+    class SessionsService {
+        /**
+         * Become user.
+         * @param {Session} session - current session of user.
+         * @param {mongo.ObjectId|String} viewedUserId - id of user to become.
+         */
+        static become(session, viewedUserId) {
+            return mongo.Account.findById(viewedUserId).exec()
+                .then((viewedUser) => {
+                    if (!session.req.user.admin)
+                        throw new errors.IllegalAccessError('Became this user is not permitted. Only administrators can perform this actions.');
+
+                    session.viewedUser = viewedUser;
+                });
+        }
+
+        /**
+         * Revert to your identity.
+         */
+        static revert(session) {
+            return new Promise((resolve) => {
+                delete session.viewedUser;
+
+                resolve();
+            });
+        }
+    }
+
+    return SessionsService;
+};

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/backend/services/spaces.js
----------------------------------------------------------------------
diff --git a/modules/web-console/backend/services/spaces.js b/modules/web-console/backend/services/spaces.js
new file mode 100644
index 0000000..863d57c
--- /dev/null
+++ b/modules/web-console/backend/services/spaces.js
@@ -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.
+ */
+
+'use strict';
+
+// Fire me up!
+
+module.exports = {
+    implements: 'services/spaces',
+    inject: ['mongo', 'errors']
+};
+
+/**
+ * @param mongo
+ * @param errors
+ * @returns {SpacesService}
+ */
+module.exports.factory = (mongo, errors) => {
+    class SpacesService {
+        /**
+         * Query for user spaces.
+         *
+         * @param {mongo.ObjectId|String} userId User ID.
+         * @param {Boolean} demo Is need use demo space.
+         * @returns {Promise}
+         */
+        static spaces(userId, demo) {
+            return mongo.Space.find({owner: userId, demo: !!demo}).lean().exec()
+                .then((spaces) => {
+                    if (!spaces.length)
+                        throw new errors.MissingResourceException('Failed to find space');
+
+                    return spaces;
+                });
+        }
+
+        /**
+         * Extract IDs from user spaces.
+         *
+         * @param {mongo.ObjectId|String} userId User ID.
+         * @param {Boolean} demo Is need use demo space.
+         * @returns {Promise}
+         */
+        static spaceIds(userId, demo) {
+            return this.spaces(userId, demo)
+                .then((spaces) => spaces.map((space) => space._id));
+        }
+
+        /**
+         * Create demo space for user
+         * @param userId - user id
+         * @returns {Promise<mongo.Space>} that resolves created demo space for user
+         */
+        static createDemoSpace(userId) {
+            return new mongo.Space({name: 'Demo space', owner: userId, demo: true}).save();
+        }
+    }
+
+    return SpacesService;
+};
+

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/backend/services/users.js
----------------------------------------------------------------------
diff --git a/modules/web-console/backend/services/users.js b/modules/web-console/backend/services/users.js
new file mode 100644
index 0000000..8058b25
--- /dev/null
+++ b/modules/web-console/backend/services/users.js
@@ -0,0 +1,229 @@
+/*
+ * 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.
+ */
+
+'use strict';
+
+// Fire me up!
+
+module.exports = {
+    implements: 'services/users',
+    inject: ['require(lodash)', 'mongo', 'settings', 'services/spaces', 'services/mails', 'agent-manager', 'errors']
+};
+
+/**
+ * @param _
+ * @param mongo
+ * @param settings
+ * @param {SpacesService} spacesService
+ * @param {MailsService} mailsService
+ * @param agentMgr
+ * @param errors
+ * @returns {UsersService}
+ */
+module.exports.factory = (_, mongo, settings, spacesService, mailsService, agentMgr, errors) => {
+    const _randomString = () => {
+        const possible = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';
+        const possibleLen = possible.length;
+
+        let res = '';
+
+        for (let i = 0; i < settings.tokenLength; i++)
+            res += possible.charAt(Math.floor(Math.random() * possibleLen));
+
+        return res;
+    };
+
+    class UsersService {
+        /**
+         * Save profile information.
+         * @param {String} host - The host
+         * @param {Object} user - The user
+         * @returns {Promise.<mongo.ObjectId>} that resolves account id of merge operation.
+         */
+        static create(host, user) {
+            return mongo.Account.count().exec()
+                .then((cnt) => {
+                    user.admin = cnt === 0;
+
+                    user.token = _randomString();
+
+                    return new mongo.Account(user);
+                })
+                .then((created) => {
+                    return new Promise((resolve, reject) => {
+                        mongo.Account.register(created, user.password, (err, registered) => {
+                            if (err)
+                                reject(err);
+
+                            if (!registered)
+                                reject(new errors.ServerErrorException('Failed to register user.'));
+
+                            resolve(registered);
+                        });
+                    });
+                })
+                .then((registered) => {
+                    registered.resetPasswordToken = _randomString();
+
+                    return registered.save()
+                        .then(() => mongo.Space.create({name: 'Personal space', owner: registered._id}))
+                        .then(() => {
+                            mailsService.emailUserSignUp(host, registered)
+                                .catch((err) => console.error(err));
+
+                            return registered;
+                        });
+                });
+        }
+
+        /**
+         * Save user.
+         * @param {Object} changed - The user
+         * @returns {Promise.<mongo.ObjectId>} that resolves account id of merge operation.
+         */
+        static save(changed) {
+            return mongo.Account.findById(changed._id).exec()
+                .then((user) => {
+                    if (!changed.password)
+                        return Promise.resolve(user);
+
+                    return new Promise((resolve, reject) => {
+                        user.setPassword(changed.password, (err, _user) => {
+                            if (err)
+                                return reject(err);
+
+                            delete changed.password;
+
+                            resolve(_user);
+                        });
+                    });
+                })
+                .then((user) => {
+                    if (!changed.email || user.email === changed.email)
+                        return Promise.resolve(user);
+
+                    return new Promise((resolve, reject) => {
+                        mongo.Account.findOne({email: changed.email}, (err, _user) => {
+                            // TODO send error to admin
+                            if (err)
+                                reject(new Error('Failed to check email!'));
+
+                            if (_user && _user._id !== user._id)
+                                reject(new Error('User with this email already registered!'));
+
+                            resolve(user);
+                        });
+                    });
+                })
+                .then((user) => {
+                    if (changed.token && user.token !== changed.token)
+                        agentMgr.close(user._id, user.token);
+
+                    _.extend(user, changed);
+
+                    return user.save();
+                });
+        }
+
+        /**
+         * Get list of user accounts and summary information.
+         * @returns {mongo.Account[]} - returns all accounts with counters object
+         */
+        static list() {
+            return Promise.all([
+                mongo.Space.aggregate([
+                    {$match: {demo: false}},
+                    {$lookup: {from: 'clusters', localField: '_id', foreignField: 'space', as: 'clusters'}},
+                    {$lookup: {from: 'caches', localField: '_id', foreignField: 'space', as: 'caches'}},
+                    {$lookup: {from: 'domainmodels', localField: '_id', foreignField: 'space', as: 'domainmodels'}},
+                    {$lookup: {from: 'igfs', localField: '_id', foreignField: 'space', as: 'igfs'}},
+                    {
+                        $project: {
+                            owner: 1,
+                            clusters: {$size: '$clusters'},
+                            models: {$size: '$domainmodels'},
+                            caches: {$size: '$caches'},
+                            igfs: {$size: '$igfs'}
+                        }
+                    }
+                ]).exec(),
+                mongo.Account.find({}).sort('firstName lastName').lean().exec()
+            ])
+                .then(([counters, users]) => {
+                    const countersMap = _.keyBy(counters, 'owner');
+
+                    _.forEach(users, (user) => {
+                        user.counters = _.omit(countersMap[user._id], '_id', 'owner');
+                    });
+
+                    return users;
+                });
+        }
+
+        /**
+         * Remove account.
+         * @param {String} host.
+         * @param {mongo.ObjectId|String} userId - The account id for remove.
+         * @returns {Promise.<{rowsAffected}>} - The number of affected rows.
+         */
+        static remove(host, userId) {
+            return mongo.Account.findByIdAndRemove(userId).exec()
+                .then((user) => {
+                    return spacesService.spaceIds(userId)
+                        .then((spaceIds) => Promise.all([
+                            mongo.Cluster.remove({space: {$in: spaceIds}}).exec(),
+                            mongo.Cache.remove({space: {$in: spaceIds}}).exec(),
+                            mongo.DomainModel.remove({space: {$in: spaceIds}}).exec(),
+                            mongo.Igfs.remove({space: {$in: spaceIds}}).exec(),
+                            mongo.Notebook.remove({space: {$in: spaceIds}}).exec(),
+                            mongo.Space.remove({owner: userId}).exec()
+                        ]))
+                        .catch((err) => console.error(`Failed to cleanup spaces [user=${user.username}, err=${err}`))
+                        .then(() => user);
+                })
+                .then((user) => mailsService.emailUserDeletion(host, user).catch((err) => console.error(err)));
+        }
+
+        /**
+         * Get account information.
+         */
+        static get(user, viewedUser) {
+            if (_.isNil(user))
+                return Promise.reject(new errors.AuthFailedException('The user profile service failed the sign in. User profile cannot be loaded.'));
+
+            const becomeUsed = viewedUser && user.admin;
+
+            if (becomeUsed) {
+                user = viewedUser;
+
+                user.becomeUsed = true;
+            }
+            else
+                user = user.toJSON();
+
+            return mongo.Space.findOne({owner: user._id, demo: true}).exec()
+                .then((demoSpace) => {
+                    if (user && demoSpace)
+                        user.demoCreated = true;
+
+                    return user;
+                });
+        }
+    }
+
+    return UsersService;
+};

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/backend/test/config/settings.json
----------------------------------------------------------------------
diff --git a/modules/web-console/backend/test/config/settings.json b/modules/web-console/backend/test/config/settings.json
new file mode 100644
index 0000000..a17a777
--- /dev/null
+++ b/modules/web-console/backend/test/config/settings.json
@@ -0,0 +1,20 @@
+{
+  "server": {
+    "port": 3000,
+    "ssl": false
+  },
+  "mongodb": {
+    "url": "mongodb://localhost/console-test"
+  },
+  "agentServer": {
+    "port": 3001,
+    "ssl": false
+  },
+  "mail": {
+    "service": "",
+    "sign": "Kind regards,<br>Apache Ignite Team",
+    "from": "Apache Ignite Web Console <so...@somecompany.tld>",
+    "user": "someusername@somecompany.tld",
+    "pass": ""
+  }
+}

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/backend/test/data/accounts.json
----------------------------------------------------------------------
diff --git a/modules/web-console/backend/test/data/accounts.json b/modules/web-console/backend/test/data/accounts.json
new file mode 100644
index 0000000..e5b7f98
--- /dev/null
+++ b/modules/web-console/backend/test/data/accounts.json
@@ -0,0 +1,18 @@
+[
+  {
+    "_id" : "57725443e6d604c05dab9ded",
+    "salt" : "ca8b49c2eacd498a0973de30c0873c166ed99fa0605981726aedcc85bee17832",
+    "hash" : "c052c87e454cd0875332719e1ce085ccd92bedb73c8f939ba45d387f724da97128280643ad4f841d929d48de802f48f4a27b909d2dc806d957d38a1a4049468ce817490038f00ac1416aaf9f8f5a5c476730b46ea22d678421cd269869d4ba9d194f73906e5d5a4fec5229459e20ebda997fb95298067126f6c15346d886d44b67def03bf3ffe484b2e4fa449985de33a0c12e4e1da4c7d71fe7af5d138433f703d8c7eeebbb3d57f1a89659010a1f1d3cd4fbc524abab07860daabb08f08a28b8bfc64ecde2ea3c103030d0d54fc24d9c02f92ee6b3aa1bcd5c70113ab9a8045faea7dd2dc59ec4f9f69fcf634232721e9fb44012f0e8c8fdf7c6bf642db6867ef8e7877123e1bc78af7604fee2e34ad0191f8b97613ea458e0fca024226b7055e08a4bdb256fabf0a203a1e5b6a6c298fb0c60308569cefba779ce1e41fb971e5d1745959caf524ab0bedafce67157922f9c505cea033f6ed28204791470d9d08d31ce7e8003df8a3a05282d4d60bfe6e2f7de06f4b18377dac0fe764ed683c9b2553e75f8280c748aa166fef6f89190b1c6d369ab86422032171e6f9686de42ac65708e63bf018a043601d85bc5c820c7ad1d51ded32e59cdaa629a3f7ae325bbc931f9f21d90c9204effdbd53721a60c8b180dd8c236133e287a47ccc9e5072eb6593771e435e4d5196
 d50d6ddb32c226651c6503387895c5ad025f69fd3",
+    "email" : "a@a",
+    "firstName" : "TestFirstName",
+    "lastName" : "TestLastName",
+    "company" : "TestCompany",
+    "country" : "Canada",
+    "admin" : true,
+    "token" : "ppw4tPI3JUOGHva8CODO",
+    "attempts" : 0,
+    "lastLogin" : "2016-06-28T10:41:07.463Z",
+    "__v" : 0,
+    "resetPasswordToken" : "892rnLbEnVp1FP75Jgpi"
+  }
+]
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/backend/test/data/caches.json
----------------------------------------------------------------------
diff --git a/modules/web-console/backend/test/data/caches.json b/modules/web-console/backend/test/data/caches.json
new file mode 100644
index 0000000..f7a8690
--- /dev/null
+++ b/modules/web-console/backend/test/data/caches.json
@@ -0,0 +1,87 @@
+[
+  {
+    "name": "CarCache",
+    "cacheMode": "PARTITIONED",
+    "atomicityMode": "ATOMIC",
+    "readThrough": true,
+    "writeThrough": true,
+    "sqlFunctionClasses": [],
+    "cacheStoreFactory": {
+      "kind": "CacheJdbcPojoStoreFactory",
+      "CacheJdbcPojoStoreFactory": {
+        "dataSourceBean": "dsH2",
+        "dialect": "H2"
+      }
+    },
+    "domains": [],
+    "clusters": []
+  },
+  {
+    "name": "ParkingCache",
+    "cacheMode": "PARTITIONED",
+    "atomicityMode": "ATOMIC",
+    "readThrough": true,
+    "writeThrough": true,
+    "sqlFunctionClasses": [],
+    "cacheStoreFactory": {
+      "kind": "CacheJdbcPojoStoreFactory",
+      "CacheJdbcPojoStoreFactory": {
+        "dataSourceBean": "dsH2",
+        "dialect": "H2"
+      }
+    },
+    "domains": [],
+    "clusters": []
+  },
+  {
+    "name": "CountryCache",
+    "cacheMode": "PARTITIONED",
+    "atomicityMode": "ATOMIC",
+    "readThrough": true,
+    "writeThrough": true,
+    "sqlFunctionClasses": [],
+    "cacheStoreFactory": {
+      "kind": "CacheJdbcPojoStoreFactory",
+      "CacheJdbcPojoStoreFactory": {
+        "dataSourceBean": "dsH2",
+        "dialect": "H2"
+      }
+    },
+    "domains": [],
+    "clusters": []
+  },
+  {
+    "name": "DepartmentCache",
+    "cacheMode": "PARTITIONED",
+    "atomicityMode": "ATOMIC",
+    "readThrough": true,
+    "writeThrough": true,
+    "sqlFunctionClasses": [],
+    "cacheStoreFactory": {
+      "kind": "CacheJdbcPojoStoreFactory",
+      "CacheJdbcPojoStoreFactory": {
+        "dataSourceBean": "dsH2",
+        "dialect": "H2"
+      }
+    },
+    "domains": [],
+    "clusters": []
+  },
+  {
+    "name": "EmployeeCache",
+    "cacheMode": "PARTITIONED",
+    "atomicityMode": "ATOMIC",
+    "readThrough": true,
+    "writeThrough": true,
+    "sqlFunctionClasses": [],
+    "cacheStoreFactory": {
+      "kind": "CacheJdbcPojoStoreFactory",
+      "CacheJdbcPojoStoreFactory": {
+        "dataSourceBean": "dsH2",
+        "dialect": "H2"
+      }
+    },
+    "domains": [],
+    "clusters": []
+  }
+]

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/backend/test/data/clusters.json
----------------------------------------------------------------------
diff --git a/modules/web-console/backend/test/data/clusters.json b/modules/web-console/backend/test/data/clusters.json
new file mode 100644
index 0000000..014b519
--- /dev/null
+++ b/modules/web-console/backend/test/data/clusters.json
@@ -0,0 +1,50 @@
+[
+  {
+    "name": "cluster-igfs",
+    "connector": {
+      "noDelay": true
+    },
+    "communication": {
+      "tcpNoDelay": true
+    },
+    "igfss": [],
+    "caches": [],
+    "binaryConfiguration": {
+      "compactFooter": true,
+      "typeConfigurations": []
+    },
+    "discovery": {
+      "kind": "Multicast",
+      "Multicast": {
+        "addresses": ["127.0.0.1:47500..47510"]
+      },
+      "Vm": {
+        "addresses": ["127.0.0.1:47500..47510"]
+      }
+    }
+  },
+  {
+    "name": "cluster-caches",
+    "connector": {
+      "noDelay": true
+    },
+    "communication": {
+      "tcpNoDelay": true
+    },
+    "igfss": [],
+    "caches": [],
+    "binaryConfiguration": {
+      "compactFooter": true,
+      "typeConfigurations": []
+    },
+    "discovery": {
+      "kind": "Multicast",
+      "Multicast": {
+        "addresses": ["127.0.0.1:47500..47510"]
+      },
+      "Vm": {
+        "addresses": ["127.0.0.1:47500..47510"]
+      }
+    }
+  }
+]

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/backend/test/data/domains.json
----------------------------------------------------------------------
diff --git a/modules/web-console/backend/test/data/domains.json b/modules/web-console/backend/test/data/domains.json
new file mode 100644
index 0000000..980d8d1
--- /dev/null
+++ b/modules/web-console/backend/test/data/domains.json
@@ -0,0 +1,307 @@
+[
+  {
+    "keyType": "Integer",
+    "valueType": "model.Parking",
+    "queryMetadata": "Configuration",
+    "databaseSchema": "CARS",
+    "databaseTable": "PARKING",
+    "indexes": [],
+    "aliases": [],
+    "fields": [
+      {
+        "name": "name",
+        "className": "String"
+      },
+      {
+        "name": "capacity",
+        "className": "Integer"
+      }
+    ],
+    "valueFields": [
+      {
+        "databaseFieldName": "NAME",
+        "databaseFieldType": "VARCHAR",
+        "javaFieldName": "name",
+        "javaFieldType": "String"
+      },
+      {
+        "databaseFieldName": "CAPACITY",
+        "databaseFieldType": "INTEGER",
+        "javaFieldName": "capacity",
+        "javaFieldType": "int"
+      }
+    ],
+    "keyFields": [
+      {
+        "databaseFieldName": "ID",
+        "databaseFieldType": "INTEGER",
+        "javaFieldName": "id",
+        "javaFieldType": "int"
+      }
+    ],
+    "caches": []
+  },
+  {
+    "keyType": "Integer",
+    "valueType": "model.Department",
+    "queryMetadata": "Configuration",
+    "databaseSchema": "PUBLIC",
+    "databaseTable": "DEPARTMENT",
+    "indexes": [],
+    "aliases": [],
+    "fields": [
+      {
+        "name": "countryId",
+        "className": "Integer"
+      },
+      {
+        "name": "name",
+        "className": "String"
+      }
+    ],
+    "valueFields": [
+      {
+        "databaseFieldName": "COUNTRY_ID",
+        "databaseFieldType": "INTEGER",
+        "javaFieldName": "countryId",
+        "javaFieldType": "int"
+      },
+      {
+        "databaseFieldName": "NAME",
+        "databaseFieldType": "VARCHAR",
+        "javaFieldName": "name",
+        "javaFieldType": "String"
+      }
+    ],
+    "keyFields": [
+      {
+        "databaseFieldName": "ID",
+        "databaseFieldType": "INTEGER",
+        "javaFieldName": "id",
+        "javaFieldType": "int"
+      }
+    ],
+    "caches": []
+  },
+  {
+    "keyType": "Integer",
+    "valueType": "model.Employee",
+    "queryMetadata": "Configuration",
+    "databaseSchema": "PUBLIC",
+    "databaseTable": "EMPLOYEE",
+    "indexes": [
+      {
+        "name": "EMP_NAMES",
+        "indexType": "SORTED",
+        "fields": [
+          {
+            "name": "firstName",
+            "direction": true
+          },
+          {
+            "name": "lastName",
+            "direction": true
+          }
+        ]
+      },
+      {
+        "name": "EMP_SALARY",
+        "indexType": "SORTED",
+        "fields": [
+          {
+            "name": "salary",
+            "direction": true
+          }
+        ]
+      }
+    ],
+    "aliases": [],
+    "fields": [
+      {
+        "name": "departmentId",
+        "className": "Integer"
+      },
+      {
+        "name": "managerId",
+        "className": "Integer"
+      },
+      {
+        "name": "firstName",
+        "className": "String"
+      },
+      {
+        "name": "lastName",
+        "className": "String"
+      },
+      {
+        "name": "email",
+        "className": "String"
+      },
+      {
+        "name": "phoneNumber",
+        "className": "String"
+      },
+      {
+        "name": "hireDate",
+        "className": "Date"
+      },
+      {
+        "name": "job",
+        "className": "String"
+      },
+      {
+        "name": "salary",
+        "className": "Double"
+      }
+    ],
+    "valueFields": [
+      {
+        "databaseFieldName": "DEPARTMENT_ID",
+        "databaseFieldType": "INTEGER",
+        "javaFieldName": "departmentId",
+        "javaFieldType": "int"
+      },
+      {
+        "databaseFieldName": "MANAGER_ID",
+        "databaseFieldType": "INTEGER",
+        "javaFieldName": "managerId",
+        "javaFieldType": "Integer"
+      },
+      {
+        "databaseFieldName": "FIRST_NAME",
+        "databaseFieldType": "VARCHAR",
+        "javaFieldName": "firstName",
+        "javaFieldType": "String"
+      },
+      {
+        "databaseFieldName": "LAST_NAME",
+        "databaseFieldType": "VARCHAR",
+        "javaFieldName": "lastName",
+        "javaFieldType": "String"
+      },
+      {
+        "databaseFieldName": "EMAIL",
+        "databaseFieldType": "VARCHAR",
+        "javaFieldName": "email",
+        "javaFieldType": "String"
+      },
+      {
+        "databaseFieldName": "PHONE_NUMBER",
+        "databaseFieldType": "VARCHAR",
+        "javaFieldName": "phoneNumber",
+        "javaFieldType": "String"
+      },
+      {
+        "databaseFieldName": "HIRE_DATE",
+        "databaseFieldType": "DATE",
+        "javaFieldName": "hireDate",
+        "javaFieldType": "Date"
+      },
+      {
+        "databaseFieldName": "JOB",
+        "databaseFieldType": "VARCHAR",
+        "javaFieldName": "job",
+        "javaFieldType": "String"
+      },
+      {
+        "databaseFieldName": "SALARY",
+        "databaseFieldType": "DOUBLE",
+        "javaFieldName": "salary",
+        "javaFieldType": "Double"
+      }
+    ],
+    "keyFields": [
+      {
+        "databaseFieldName": "ID",
+        "databaseFieldType": "INTEGER",
+        "javaFieldName": "id",
+        "javaFieldType": "int"
+      }
+    ],
+    "caches": []
+  },
+  {
+    "keyType": "Integer",
+    "valueType": "model.Country",
+    "queryMetadata": "Configuration",
+    "databaseSchema": "PUBLIC",
+    "databaseTable": "COUNTRY",
+    "indexes": [],
+    "aliases": [],
+    "fields": [
+      {
+        "name": "name",
+        "className": "String"
+      },
+      {
+        "name": "population",
+        "className": "Integer"
+      }
+    ],
+    "valueFields": [
+      {
+        "databaseFieldName": "NAME",
+        "databaseFieldType": "VARCHAR",
+        "javaFieldName": "name",
+        "javaFieldType": "String"
+      },
+      {
+        "databaseFieldName": "POPULATION",
+        "databaseFieldType": "INTEGER",
+        "javaFieldName": "population",
+        "javaFieldType": "int"
+      }
+    ],
+    "keyFields": [
+      {
+        "databaseFieldName": "ID",
+        "databaseFieldType": "INTEGER",
+        "javaFieldName": "id",
+        "javaFieldType": "int"
+      }
+    ],
+    "caches": []
+  },
+  {
+    "keyType": "Integer",
+    "valueType": "model.Car",
+    "queryMetadata": "Configuration",
+    "databaseSchema": "CARS",
+    "databaseTable": "CAR",
+    "indexes": [],
+    "aliases": [],
+    "fields": [
+      {
+        "name": "parkingId",
+        "className": "Integer"
+      },
+      {
+        "name": "name",
+        "className": "String"
+      }
+    ],
+    "valueFields": [
+      {
+        "databaseFieldName": "PARKING_ID",
+        "databaseFieldType": "INTEGER",
+        "javaFieldName": "parkingId",
+        "javaFieldType": "int"
+      },
+      {
+        "databaseFieldName": "NAME",
+        "databaseFieldType": "VARCHAR",
+        "javaFieldName": "name",
+        "javaFieldType": "String"
+      }
+    ],
+    "keyFields": [
+      {
+        "databaseFieldName": "ID",
+        "databaseFieldType": "INTEGER",
+        "javaFieldName": "id",
+        "javaFieldType": "int"
+      }
+    ],
+    "caches": []
+  }
+]

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/backend/test/data/igfss.json
----------------------------------------------------------------------
diff --git a/modules/web-console/backend/test/data/igfss.json b/modules/web-console/backend/test/data/igfss.json
new file mode 100644
index 0000000..cd128a6
--- /dev/null
+++ b/modules/web-console/backend/test/data/igfss.json
@@ -0,0 +1,10 @@
+[
+  {
+    "ipcEndpointEnabled": true,
+    "fragmentizerEnabled": true,
+    "name": "igfs",
+    "dataCacheName": "igfs-data",
+    "metaCacheName": "igfs-meta",
+    "clusters": []
+  }
+]

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/backend/test/injector.js
----------------------------------------------------------------------
diff --git a/modules/web-console/backend/test/injector.js b/modules/web-console/backend/test/injector.js
new file mode 100644
index 0000000..8d44d31
--- /dev/null
+++ b/modules/web-console/backend/test/injector.js
@@ -0,0 +1,31 @@
+/*
+ * 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 path from 'path';
+import fireUp from 'fire-up';
+
+module.exports = fireUp.newInjector({
+    basePath: path.join(__dirname, '../'),
+    modules: [
+        './app/**/*.js',
+        './config/**/*.js',
+        './errors/**/*.js',
+        './middlewares/**/*.js',
+        './routes/**/*.js',
+        './services/**/*.js'
+    ]
+});

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/backend/test/unit/CacheService.test.js
----------------------------------------------------------------------
diff --git a/modules/web-console/backend/test/unit/CacheService.test.js b/modules/web-console/backend/test/unit/CacheService.test.js
new file mode 100644
index 0000000..1442775
--- /dev/null
+++ b/modules/web-console/backend/test/unit/CacheService.test.js
@@ -0,0 +1,192 @@
+/*
+ * 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 {assert} from 'chai';
+import injector from '../injector';
+import testCaches from '../data/caches.json';
+import testAccounts from '../data/accounts.json';
+
+let cacheService;
+let mongo;
+let errors;
+
+suite('CacheServiceTestsSuite', () => {
+    const prepareUserSpaces = () => {
+        return mongo.Account.create(testAccounts)
+            .then((accounts) => {
+                return Promise.all(
+                    accounts.map((account) => mongo.Space.create(
+                        [
+                            {name: 'Personal space', owner: account._id, demo: false},
+                            {name: 'Demo space', owner: account._id, demo: true}
+                        ]
+                    )))
+                    .then((spaces) => [accounts, spaces]);
+            });
+    };
+
+    suiteSetup(() => {
+        return Promise.all([injector('services/caches'),
+            injector('mongo'),
+            injector('errors')])
+            .then(([_cacheService, _mongo, _errors]) => {
+                mongo = _mongo;
+                cacheService = _cacheService;
+                errors = _errors;
+            });
+    });
+
+    setup(() => {
+        return Promise.all([
+            mongo.Cache.remove().exec(),
+            mongo.Account.remove().exec(),
+            mongo.Space.remove().exec()
+        ]);
+    });
+
+    test('Create new cache', (done) => {
+        cacheService.merge(testCaches[0])
+            .then((cache) => {
+                assert.isNotNull(cache._id);
+
+                return cache._id;
+            })
+            .then((cacheId) => mongo.Cache.findById(cacheId))
+            .then((cache) => {
+                assert.isNotNull(cache);
+            })
+            .then(done)
+            .catch(done);
+    });
+
+    test('Update existed cache', (done) => {
+        const newName = 'NewUniqueName';
+
+        cacheService.merge(testCaches[0])
+            .then((cache) => {
+                const cacheBeforeMerge = {...testCaches[0], _id: cache._id, name: newName};
+
+                return cacheService.merge(cacheBeforeMerge);
+            })
+            .then((cache) => mongo.Cache.findById(cache._id))
+            .then((cacheAfterMerge) => {
+                assert.equal(cacheAfterMerge.name, newName);
+            })
+            .then(done)
+            .catch(done);
+    });
+
+    test('Create duplicated cache', (done) => {
+        cacheService.merge(testCaches[0])
+            .then(() => cacheService.merge(testCaches[0]))
+            .catch((err) => {
+                assert.instanceOf(err, errors.DuplicateKeyException);
+
+                done();
+            });
+    });
+
+    test('Remove existed cache', (done) => {
+        cacheService.merge(testCaches[0])
+            .then((createdCache) => {
+                return mongo.Cache.findById(createdCache._id)
+                    .then((foundCache) => foundCache._id)
+                    .then(cacheService.remove)
+                    .then(({rowsAffected}) => {
+                        assert.equal(rowsAffected, 1);
+                    })
+                    .then(() => mongo.Cache.findById(createdCache._id))
+                    .then((notFoundCache) => {
+                        assert.isNull(notFoundCache);
+                    });
+            })
+            .then(done)
+            .catch(done);
+    });
+
+    test('Remove cache without identifier', (done) => {
+        cacheService.merge(testCaches[0])
+            .then(() => cacheService.remove())
+            .catch((err) => {
+                assert.instanceOf(err, errors.IllegalArgumentException);
+
+                done();
+            });
+    });
+
+    test('Remove missed cache', (done) => {
+        const validNoExistingId = 'FFFFFFFFFFFFFFFFFFFFFFFF';
+
+        cacheService.merge(testCaches[0])
+            .then(() => cacheService.remove(validNoExistingId))
+            .then(({rowsAffected}) => {
+                assert.equal(rowsAffected, 0);
+            })
+            .then(done)
+            .catch(done);
+    });
+
+    test('Remove all caches in space', (done) => {
+        prepareUserSpaces()
+            .then(([accounts, spaces]) => {
+                const currentUser = accounts[0];
+                const userCache = {...testCaches[0], space: spaces[0][0]._id};
+
+                return cacheService.merge(userCache)
+                    .then(() => cacheService.removeAll(currentUser._id, false));
+            })
+            .then(({rowsAffected}) => {
+                assert.equal(rowsAffected, 1);
+            })
+            .then(done)
+            .catch(done);
+    });
+
+    test('Get all caches by space', (done) => {
+        prepareUserSpaces()
+            .then(([accounts, spaces]) => {
+                const userCache = {...testCaches[0], space: spaces[0][0]._id};
+
+                return cacheService.merge(userCache)
+                    .then((cache) => {
+                        return cacheService.listBySpaces(spaces[0][0]._id)
+                            .then((caches) => {
+                                assert.equal(caches.length, 1);
+                                assert.equal(caches[0]._id.toString(), cache._id.toString());
+                            });
+                    });
+            })
+            .then(done)
+            .catch(done);
+    });
+
+    test('Update linked entities on update cache', (done) => {
+        // TODO IGNITE-3262 Add test.
+        done();
+    });
+
+    test('Update linked entities on remove cache', (done) => {
+        // TODO IGNITE-3262 Add test.
+        done();
+    });
+
+    test('Update linked entities on remove all caches in space', (done) => {
+        // TODO IGNITE-3262 Add test.
+        done();
+    });
+});

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/backend/test/unit/ClusterService.test.js
----------------------------------------------------------------------
diff --git a/modules/web-console/backend/test/unit/ClusterService.test.js b/modules/web-console/backend/test/unit/ClusterService.test.js
new file mode 100644
index 0000000..ab0e912
--- /dev/null
+++ b/modules/web-console/backend/test/unit/ClusterService.test.js
@@ -0,0 +1,190 @@
+/*
+ * 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 {assert} from 'chai';
+import injector from '../injector';
+import testClusters from '../data/clusters.json';
+import testAccounts from '../data/accounts.json';
+
+let clusterService;
+let mongo;
+let errors;
+
+suite('ClusterServiceTestsSuite', () => {
+    const prepareUserSpaces = () => {
+        return mongo.Account.create(testAccounts)
+            .then((accounts) => {
+                return Promise.all(accounts.map((account) => mongo.Space.create(
+                    [
+                        {name: 'Personal space', owner: account._id, demo: false},
+                        {name: 'Demo space', owner: account._id, demo: true}
+                    ]
+                )))
+                    .then((spaces) => [accounts, spaces]);
+            });
+    };
+
+    suiteSetup(() => {
+        return Promise.all([injector('services/clusters'),
+            injector('mongo'),
+            injector('errors')])
+            .then(([_clusterService, _mongo, _errors]) => {
+                mongo = _mongo;
+                clusterService = _clusterService;
+                errors = _errors;
+            });
+    });
+
+    setup(() => {
+        return Promise.all([
+            mongo.Cluster.remove().exec(),
+            mongo.Account.remove().exec(),
+            mongo.Space.remove().exec()
+        ]);
+    });
+
+    test('Create new cluster', (done) => {
+        clusterService.merge(testClusters[0])
+            .then((cluster) => {
+                assert.isNotNull(cluster._id);
+
+                return cluster._id;
+            })
+            .then((clusterId) => mongo.Cluster.findById(clusterId))
+            .then((cluster) => {
+                assert.isNotNull(cluster);
+            })
+            .then(done)
+            .catch(done);
+    });
+
+    test('Update existed cluster', (done) => {
+        const newName = 'NewUniqueName';
+
+        clusterService.merge(testClusters[0])
+            .then((cluster) => {
+                const clusterBeforeMerge = {...testClusters[0], _id: cluster._id, name: newName};
+
+                return clusterService.merge(clusterBeforeMerge);
+            })
+            .then((cluster) => mongo.Cluster.findById(cluster._id))
+            .then((clusterAfterMerge) => {
+                assert.equal(clusterAfterMerge.name, newName);
+            })
+            .then(done)
+            .catch(done);
+    });
+
+    test('Create duplicated cluster', (done) => {
+        clusterService.merge(testClusters[0])
+            .then(() => clusterService.merge(testClusters[0]))
+            .catch((err) => {
+                assert.instanceOf(err, errors.DuplicateKeyException);
+
+                done();
+            });
+    });
+
+    test('Remove existed cluster', (done) => {
+        clusterService.merge(testClusters[0])
+            .then((existCluster) => {
+                return mongo.Cluster.findById(existCluster._id)
+                    .then((foundCluster) => clusterService.remove(foundCluster._id))
+                    .then(({rowsAffected}) => {
+                        assert.equal(rowsAffected, 1);
+                    })
+                    .then(() => mongo.Cluster.findById(existCluster._id))
+                    .then((notFoundCluster) => {
+                        assert.isNull(notFoundCluster);
+                    });
+            })
+            .then(done)
+            .catch(done);
+    });
+
+    test('Remove cluster without identifier', (done) => {
+        clusterService.merge(testClusters[0])
+            .then(() => clusterService.remove())
+            .catch((err) => {
+                assert.instanceOf(err, errors.IllegalArgumentException);
+
+                done();
+            });
+    });
+
+    test('Remove missed cluster', (done) => {
+        const validNoExistingId = 'FFFFFFFFFFFFFFFFFFFFFFFF';
+
+        clusterService.merge(testClusters[0])
+            .then(() => clusterService.remove(validNoExistingId))
+            .then(({rowsAffected}) => {
+                assert.equal(rowsAffected, 0);
+            })
+            .then(done)
+            .catch(done);
+    });
+
+    test('Remove all clusters in space', (done) => {
+        prepareUserSpaces()
+            .then(([accounts, spaces]) => {
+                const currentUser = accounts[0];
+                const userCluster = {...testClusters[0], space: spaces[0][0]._id};
+
+                return clusterService.merge(userCluster)
+                    .then(() => clusterService.removeAll(currentUser._id, false));
+            })
+            .then(({rowsAffected}) => {
+                assert.equal(rowsAffected, 1);
+            })
+            .then(done)
+            .catch(done);
+    });
+
+    test('Get all clusters by space', (done) => {
+        prepareUserSpaces()
+            .then(([accounts, spaces]) => {
+                const userCluster = {...testClusters[0], space: spaces[0][0]._id};
+
+                return clusterService.merge(userCluster)
+                    .then((existCluster) => {
+                        return clusterService.listBySpaces(spaces[0][0]._id)
+                            .then((clusters) => {
+                                assert.equal(clusters.length, 1);
+                                assert.equal(clusters[0]._id.toString(), existCluster._id.toString());
+                            });
+                    });
+            })
+            .then(done)
+            .catch(done);
+    });
+
+    test('Update linked entities on update cluster', (done) => {
+        // TODO IGNITE-3262 Add test.
+        done();
+    });
+
+    test('Update linked entities on remove cluster', (done) => {
+        // TODO IGNITE-3262 Add test.
+        done();
+    });
+
+    test('Update linked entities on remove all clusters in space', (done) => {
+        // TODO IGNITE-3262 Add test.
+        done();
+    });
+});

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/backend/test/unit/DomainService.test.js
----------------------------------------------------------------------
diff --git a/modules/web-console/backend/test/unit/DomainService.test.js b/modules/web-console/backend/test/unit/DomainService.test.js
new file mode 100644
index 0000000..477b454
--- /dev/null
+++ b/modules/web-console/backend/test/unit/DomainService.test.js
@@ -0,0 +1,198 @@
+/*
+ * 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 {assert} from 'chai';
+import injector from '../injector';
+import testDomains from '../data/domains.json';
+import testAccounts from '../data/accounts.json';
+
+let domainService;
+let mongo;
+let errors;
+
+suite('DomainsServiceTestsSuite', () => {
+    const prepareUserSpaces = () => {
+        return mongo.Account.create(testAccounts)
+            .then((accounts) => {
+                return Promise.all(accounts.map((account) => mongo.Space.create(
+                    [
+                        {name: 'Personal space', owner: account._id, demo: false},
+                        {name: 'Demo space', owner: account._id, demo: true}
+                    ]
+                )))
+                    .then((spaces) => [accounts, spaces]);
+            });
+    };
+
+    suiteSetup(() => {
+        return Promise.all([injector('services/domains'),
+            injector('mongo'),
+            injector('errors')])
+            .then(([_domainService, _mongo, _errors]) => {
+                mongo = _mongo;
+                domainService = _domainService;
+                errors = _errors;
+            });
+    });
+
+    setup(() => {
+        return Promise.all([
+            mongo.DomainModel.remove().exec(),
+            mongo.Account.remove().exec(),
+            mongo.Space.remove().exec()
+        ]);
+    });
+
+    test('Create new domain', (done) => {
+        domainService.batchMerge([testDomains[0]])
+            .then((results) => {
+                const domain = results.savedDomains[0];
+
+                assert.isNotNull(domain._id);
+
+                return domain._id;
+            })
+            .then((domainId) => mongo.DomainModel.findById(domainId))
+            .then((domain) => {
+                assert.isNotNull(domain);
+            })
+            .then(done)
+            .catch(done);
+    });
+
+    test('Update existed domain', (done) => {
+        const newValType = 'value.Type';
+
+        domainService.batchMerge([testDomains[0]])
+            .then((results) => {
+                const domain = results.savedDomains[0];
+
+                const domainBeforeMerge = {...testDomains[0], _id: domain._id, valueType: newValType};
+
+                return domainService.batchMerge([domainBeforeMerge]);
+            })
+            .then((results) => mongo.DomainModel.findById(results.savedDomains[0]._id))
+            .then((domainAfterMerge) => {
+                assert.equal(domainAfterMerge.valueType, newValType);
+            })
+            .then(done)
+            .catch(done);
+    });
+
+    test('Create duplicated domain', (done) => {
+        domainService.batchMerge([testDomains[0]])
+            .then(() => domainService.batchMerge([testDomains[0]]))
+            .catch((err) => {
+                assert.instanceOf(err, errors.DuplicateKeyException);
+
+                done();
+            });
+    });
+
+    test('Remove existed domain', (done) => {
+        domainService.batchMerge([testDomains[0]])
+            .then((results) => {
+                const domain = results.savedDomains[0];
+
+                return mongo.DomainModel.findById(domain._id)
+                    .then((foundDomain) => domainService.remove(foundDomain._id))
+                    .then(({rowsAffected}) => {
+                        assert.equal(rowsAffected, 1);
+                    })
+                    .then(() => mongo.DomainModel.findById(domain._id))
+                    .then((notFoundDomain) => {
+                        assert.isNull(notFoundDomain);
+                    });
+            })
+            .then(done)
+            .catch(done);
+    });
+
+    test('Remove domain without identifier', (done) => {
+        domainService.batchMerge([testDomains[0]])
+            .then(() => domainService.remove())
+            .catch((err) => {
+                assert.instanceOf(err, errors.IllegalArgumentException);
+
+                done();
+            });
+    });
+
+    test('Remove missed domain', (done) => {
+        const validNoExistingId = 'FFFFFFFFFFFFFFFFFFFFFFFF';
+
+        domainService.batchMerge([testDomains[0]])
+            .then(() => domainService.remove(validNoExistingId))
+            .then(({rowsAffected}) => {
+                assert.equal(rowsAffected, 0);
+            })
+            .then(done)
+            .catch(done);
+    });
+
+    test('Remove all domains in space', (done) => {
+        prepareUserSpaces()
+            .then(([accounts, spaces]) => {
+                const currentUser = accounts[0];
+                const userDomain = {...testDomains[0], space: spaces[0][0]._id};
+
+                return domainService.batchMerge([userDomain])
+                    .then(() => domainService.removeAll(currentUser._id, false));
+            })
+            .then(({rowsAffected}) => {
+                assert.equal(rowsAffected, 1);
+            })
+            .then(done)
+            .catch(done);
+    });
+
+    test('Get all domains by space', (done) => {
+        prepareUserSpaces()
+            .then(([accounts, spaces]) => {
+                const userDomain = {...testDomains[0], space: spaces[0][0]._id};
+
+                return domainService.batchMerge([userDomain])
+                    .then((results) => {
+                        const domain = results.savedDomains[0];
+
+                        return domainService.listBySpaces(spaces[0][0]._id)
+                            .then((domains) => {
+                                assert.equal(domains.length, 1);
+                                assert.equal(domains[0]._id.toString(), domain._id.toString());
+                            });
+                    });
+            })
+            .then(done)
+            .catch(done);
+    });
+
+    test('Update linked entities on update domain', (done) => {
+        // TODO IGNITE-3262 Add test.
+        done();
+    });
+
+    test('Update linked entities on remove domain', (done) => {
+        // TODO IGNITE-3262 Add test.
+        done();
+    });
+
+    test('Update linked entities on remove all domains in space', (done) => {
+        // TODO IGNITE-3262 Add test.
+        done();
+    });
+});


[03/52] ignite git commit: Web Console beta-3.

Posted by ak...@apache.org.
http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/src/main/js/views/configuration/summary-tabs.jade
----------------------------------------------------------------------
diff --git a/modules/web-console/src/main/js/views/configuration/summary-tabs.jade b/modules/web-console/src/main/js/views/configuration/summary-tabs.jade
deleted file mode 100644
index 847b42f..0000000
--- a/modules/web-console/src/main/js/views/configuration/summary-tabs.jade
+++ /dev/null
@@ -1,25 +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.
-
-ul.nav(ng-class='$navClass', role='tablist')
-    li(role='presentation' ng-repeat='$pane in $panes track by $index' ng-class='[ $isActive($pane, $index) ? $activeClass : "", $pane.disabled ? "disabled" : "" ]')
-        a.summary-tab(ng-show='$pane.title != "POJO" || (cluster | hasPojo)' ng-switch='$pane.title' role='tab' data-toggle='tab' ng-click='!$pane.disabled && $setActive($pane.name || $index)' data-index='{{ $index }}' aria-controls='$pane.title') {{$pane.title}}
-            img(ng-switch-when='XML' src='/images/xml.png')
-            img(ng-switch-when='Java' src='/images/java.png')
-            img(ng-switch-when='POM' src='/images/xml.png')
-            img(ng-switch-when='POJO' src='/images/java.png')
-            img(ng-switch-when='Dockerfile' src='/images/docker.png')
-.tab-content(ng-transclude style='fontSize: 12px; min-height: 25em')

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/src/main/js/views/configuration/summary.jade
----------------------------------------------------------------------
diff --git a/modules/web-console/src/main/js/views/configuration/summary.jade b/modules/web-console/src/main/js/views/configuration/summary.jade
deleted file mode 100644
index f367e67..0000000
--- a/modules/web-console/src/main/js/views/configuration/summary.jade
+++ /dev/null
@@ -1,152 +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.
-
-include ../../app/helpers/jade/mixins.jade
-
-mixin hard-link(ref, txt)
-    a(style='color:#ec1c24' href=ref target='_blank') #{txt}
-
-.docs-header
-    h1 Configurations Summary
-.docs-body
-    ignite-information
-        ul
-            li Preview XML configurations for #[a(href='https://apacheignite.readme.io/docs/clients-vs-servers' target='_blank') server and client] nodes
-            li Preview code configuration
-            li Preview #[a(href='https://apacheignite.readme.io/docs/docker-deployment' target='_blank') Docker file]
-            li Preview POM dependencies
-            li Download ready-to-use Maven project
-
-    hr
-    .padding-dflt(ng-if='ui.ready && (!clusters || clusters.length == 0)')
-        | You have no clusters configured. Please configure them #[a(ui-sref='base.configuration.clusters') here].
-
-    div(ng-show='clusters && clusters.length > 0' ignite-loading='summaryPage' ignite-loading-text='Loading summary screen...' ignite-loading-position='top')
-        +main-table('clusters', 'clustersView', 'clusterName', 'selectItem(row)', '{{$index + 1}}) {{row.name}}', 'name')
-        div(ng-show='selectedItem && contentVisible(displayedRows, selectedItem)')
-            .padding-top-dflt(bs-affix)
-                button.btn.btn-primary(id='download' ng-click='downloadConfiguration()' bs-tooltip='' data-title='Download project' data-placement='bottom') Download project
-                .btn.btn-primary(bs-tooltip='' data-title='Preview generated project structure' data-placement='bottom')
-                    div(bs-popover data-template-url='/configuration/summary-project-structure.html', data-placement='bottom', data-trigger='click' data-auto-close='true')
-                        i.fa.fa-sitemap
-                        label.tipLabel Project structure
-                button.btn.btn-primary(id='proprietary-jdbc-drivers' ng-if='downloadJdbcDriversVisible()' ng-click='downloadJdbcDrivers()' bs-tooltip='' data-title='Open proprietary JDBC drivers download pages' data-placement='bottom') Download JDBC drivers
-                hr
-            .bs-affix-fix
-            .panel-group(bs-collapse ng-init='ui.activePanels=[0,1]' ng-model='ui.activePanels' data-allow-multiple='true')
-                .panel.panel-default
-                    .panel-heading(role='tab' bs-collapse-toggle)
-                        ignite-form-panel-chevron
-                        label Server
-
-                    .panel-collapse(id='server' role='tabpanel' bs-collapse-target)
-                        ignite-ui-ace-tabs.summary-tabs
-                            div(bs-tabs data-bs-active-pane="tabsServer.activeTab" template='configuration/summary-tabs.html')
-                                div(bs-pane title='XML')
-                                    ignite-ui-ace-xml(ng-if='tabsServer.activeTab == 0 || tabsServer.init[0]' ng-init='tabsServer.init[0] = true' data-master='cluster' data-no-deep-watch)
-                                div(bs-pane title='Java')
-                                    ignite-ui-ace-java(ng-if='tabsServer.activeTab == 1 || tabsServer.init[1]' ng-init='tabsServer.init[1] = true' data-master='cluster' data-no-deep-watch)
-                                div(bs-pane title='POM')
-                                    ignite-ui-ace-pom(ng-if='tabsServer.activeTab == 2 || tabsServer.init[2]' ng-init='tabsServer.init[2] = true' data-cluster='cluster' data-no-deep-watch)
-                                div(bs-pane title='Dockerfile')
-                                    ignite-ui-ace-docker(ng-if='tabsServer.activeTab == 3 || tabsServer.init[3]' ng-init='tabsServer.init[3] = true' data-cluster='cluster' data-no-deep-watch ng-model='ctrl.data.docker')
-
-                .panel.panel-default
-                    .panel-heading(role='tab' bs-collapse-toggle)
-                        ignite-form-panel-chevron
-                        label Client
-
-                    .panel-collapse(id='client' role='tabpanel' bs-collapse-target)
-                        form(name='clientForm' novalidate)
-                            -var nearCfg = 'ctrl.cluster.clientNearCfg'
-                            -var nearCfgEvictionPolicy = nearCfg + '.nearEvictionPolicy[' + nearCfg + '.nearEvictionPolicy.kind]'
-
-                            .group-content
-                                .settings-row
-                                    ignite-form-field.col-xs-8.col-sm-8.col-md-7(data-label='Near cache start size')
-                                        ignite-form-field-tooltip
-                                            | Initial cache size for near cache which will be used to pre-create internal hash table after start
-                                        ignite-form-field-input-number(
-                                            data-name='nearStartSize'
-                                            data-ng-model='#{nearCfg}.nearStartSize'
-                                            data-placeholder='375000'
-                                        )
-
-                                .settings-row
-                                    ignite-form-field.col-xs-8.col-sm-8.col-md-7(data-label='Near cache eviction policy')
-                                        ignite-form-field-tooltip
-                                            | Near cache eviction policy
-                                        ignite-form-field-dropdown(
-                                            data-id='evictionPolicies'
-                                            data-name='evictionPolicies'
-                                            data-placeholder='Not set'
-                                            data-options='[\
-                                                {value: "LRU", label: "LRU"},\
-                                                {value: "FIFO", label: "FIFO"},\
-                                                {value: "SORTED", label: "Sorted"},\
-                                                {value: undefined, label: "Not set"}\
-                                            ]'
-                                            data-ng-model='#{nearCfg}.nearEvictionPolicy.kind'
-                                        )
-                                    span(ng-if='#{nearCfg}.nearEvictionPolicy.kind')
-                                        a.customize(
-                                            ng-show='ctrl.__form.expanded'
-                                            ng-click='ctrl.__form.expanded = false'
-                                        ) Hide settings
-                                        a.customize(
-                                            ng-hide='ctrl.__form.expanded'
-                                            ng-click='ctrl.__form.expanded = true'
-                                        ) Show settings
-
-                                .settings-row
-                                    .panel-details.col-xs-12.col-sm-12.col-md-7(ng-if='ctrl.__form.expanded && #{nearCfg}.nearEvictionPolicy.kind')
-                                        .details-row
-                                            ignite-form-field(data-label='Batch size')
-                                                ignite-form-field-tooltip
-                                                    | Number of entries to remove on shrink
-                                                ignite-form-field-input-number(
-                                                    data-name='batchSize'
-                                                    data-ng-model='#{nearCfgEvictionPolicy}.batchSize'
-                                                    data-placeholder='1'
-                                                )
-                                        .details-row
-                                            ignite-form-field(data-label='Max memory size')
-                                                ignite-form-field-tooltip
-                                                    | Maximum allowed cache size in bytes
-                                                ignite-form-field-input-number(
-                                                    data-name='maxMemorySize'
-                                                    data-ng-model='#{nearCfgEvictionPolicy}.maxMemorySize'
-                                                    data-placeholder='0'
-                                                )
-                                        .details-row
-                                            ignite-form-field(data-label='Max size')
-                                                ignite-form-field-tooltip
-                                                    | Maximum allowed size of cache before entry will start getting evicted
-                                                ignite-form-field-input-number(
-                                                    data-name='maxSize'
-                                                    data-ng-model='#{nearCfgEvictionPolicy}.maxSize'
-                                                    data-placeholder='100000'
-                                                )
-                        .summary-tabs(ignite-ui-ace-tabs)
-                            div(bs-tabs data-bs-active-pane="tabsClient.activeTab" template='configuration/summary-tabs.html')
-                                div(bs-pane title='XML')
-                                    ignite-ui-ace-xml(ng-if='tabsClient.activeTab == 0 || tabsClient.init[0]' ng-init='tabsClient.init[0] = true' data-master='cluster' data-no-deep-watch data-cluster-cfg='#{nearCfg}')
-                                div(bs-pane title='Java')
-                                    ignite-ui-ace-java(ng-if='tabsClient.activeTab == 1 || tabsClient.init[1]' ng-init='tabsClient.init[1] = true' data-master='cluster' data-no-deep-watch data-cluster-cfg='#{nearCfg}')
-                                div(bs-pane title='POM')
-                                    ignite-ui-ace-pom(ng-if='tabsClient.activeTab == 2 || tabsClient.init[2]' ng-init='tabsClient.init[2] = true' data-cluster='cluster' data-no-deep-watch)
-                                div(bs-pane title='POJO' ng-if='cluster | hasPojo')
-                                    ignite-ui-ace-pojos(ng-if='tabsClient.activeTab == 3 || tabsClient.init[3]' ng-init='tabsClient.init[3] = true' data-cluster='cluster' data-no-deep-watch ng-model='ctrl.data.pojos')

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/src/main/js/views/includes/footer.jade
----------------------------------------------------------------------
diff --git a/modules/web-console/src/main/js/views/includes/footer.jade b/modules/web-console/src/main/js/views/includes/footer.jade
deleted file mode 100644
index 4ef3bf6..0000000
--- a/modules/web-console/src/main/js/views/includes/footer.jade
+++ /dev/null
@@ -1,23 +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.
-
-.container.container-footer
-    footer
-        .col-md-offset-1.col-md-10
-            ignite-footer
-        .col-md-1
-            .pull-right
-                ignite-powered-by-apache

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/src/main/js/views/includes/header.jade
----------------------------------------------------------------------
diff --git a/modules/web-console/src/main/js/views/includes/header.jade b/modules/web-console/src/main/js/views/includes/header.jade
deleted file mode 100644
index e224f64..0000000
--- a/modules/web-console/src/main/js/views/includes/header.jade
+++ /dev/null
@@ -1,51 +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.
-
-header#header.header
-    .viewedUser(ng-show='$root.user.becomeUsed')
-        | Currently assuming #[strong {{$root.user.firstName}} {{$root.user.lastName}}], #[a(ng-click='$root.revertIdentity()') revert to your identity].
-    table.container
-        tr
-            td.col-xs-3.col-sm-3.col-md-2
-                ignite-header-logo
-            td(ng-if='$root.user' style='padding-top: 20px')
-                ul.nav.navbar-nav(ignite-sidebar ignite-navbar)
-                    li(ng-class='{active: $state.includes("base.configuration")}' bs-dropdown='sidebar.items' data-placement='bottom-right' data-trigger='hover focus' data-container='self' data-animation='' ng-click='$event.stopPropagation()')
-                        a.dropdown-toggle Configuration
-                            span.caret
-
-                ul.nav.navbar-nav(ng-controller='notebooks')
-                    li.sql-notebooks(ng-if='IgniteDemoMode' ng-class='{active: $state.includes("base.sql")}')
-                        a(ui-sref='base.sql.demo') SQL
-
-                    li.sql-notebooks(ng-if='!IgniteDemoMode && !notebooks.length' ng-class='{active: $state.includes("base.sql")}')
-                        a(ng-click='inputNotebookName()') SQL
-
-                    li.sql-notebooks(ng-if='!IgniteDemoMode && notebooks.length' ng-class='{active: $state.includes("base.sql")}' bs-dropdown='notebookDropdown' data-placement='bottom-left' data-trigger='hover focus' data-container='self' data-animation='' ng-click='$event.stopPropagation()')
-                        a.dropdown-toggle SQL
-                            span.caret
-
-                    li(ui-sref-active='active'  ng-repeat='item in navbar.items')
-                        a(ui-sref='{{::item.sref}}') {{::item.text}}
-
-                a(ng-controller='demoController')
-                    button.btn.btn-info(ng-if='IgniteDemoMode' ng-click='closeDemo()') Close demo
-                    button.btn.btn-info(ng-if='!IgniteDemoMode' ng-click='startDemo()') Start demo
-
-                ul.nav.navbar-nav.pull-right(ignite-userbar)
-                    li(bs-dropdown='userbar.items' data-placement='bottom-right' data-trigger='hover focus' data-container='self' data-animation='' ng-class='{active: $state.includes("settings")}' ng-click='$event.stopPropagation()')
-                        a.dropdown-toggle {{user.firstName}} {{user.lastName}}
-                            span.caret

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/src/main/js/views/index.jade
----------------------------------------------------------------------
diff --git a/modules/web-console/src/main/js/views/index.jade b/modules/web-console/src/main/js/views/index.jade
deleted file mode 100644
index 707bfac..0000000
--- a/modules/web-console/src/main/js/views/index.jade
+++ /dev/null
@@ -1,48 +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.
-
-doctype html
-html(ng-app='ignite-console' id='app' ng-strict-di)
-    head
-        base(href='/')
-
-        meta(http-equiv='content-type' content='text/html; charset=UTF8')
-        meta(http-equiv='content-language' content='en')
-
-        title(ng-bind='$meta.title')
-
-        meta(name='fragment' content='!')
-        meta(name='description' content='{{$meta.description}}')
-        meta(name='keywords' content='{{$meta.keywords}}')
-        meta(ng-repeat='(key, value) in $meta.properties' name='{{::key}}' content='{{::value}}')
-
-    body.theme-line.body-overlap.greedy
-
-        .splash.splash-max-foreground(hide-on-state-change)
-            .splash-wrapper
-                .spinner
-                    .bounce1
-                    .bounce2
-                    .bounce3
-
-                .splash-wellcome Loading...
-
-
-        .ribbon-wrapper.right(ng-cloak)
-            .ribbon(ng-style='IgniteDemoMode && {"background": "#1b6d88"}')
-                label {{IgniteDemoMode ? "Demo" : "Beta" }}
-
-        .wrapper(ui-view='')

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/src/main/js/views/reset.jade
----------------------------------------------------------------------
diff --git a/modules/web-console/src/main/js/views/reset.jade b/modules/web-console/src/main/js/views/reset.jade
deleted file mode 100644
index 9098105..0000000
--- a/modules/web-console/src/main/js/views/reset.jade
+++ /dev/null
@@ -1,48 +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.
-
-header#header.header
-    table.container
-        tr
-            td.col-xs-3.col-sm-3.col-md-2
-                ignite-header-logo
-            td
-                ignite-header-title
-
-.container.body-container
-    .main-content(ng-controller='resetPassword')
-        .row
-            .text-center(ng-if='!token')
-                p Further instructions for password reset have been sent to your e-mail address.
-            .text-center(ng-if='error')
-                p {{::error}}
-            div(ng-if='token && !error')
-                form.form-horizontal(name='resetForm' ng-init='reset_info.token = token')
-                    .settings-row
-                        label.col-sm-1 E-mail:
-                        label {{::email}}
-                    .settings-row
-                        label.col-sm-1.required Password:
-                        .col-sm-3
-                            input#user_password.form-control(ignite-on-enter-focus-move='user_confirm' type='password' ng-model='reset_info.password' placeholder='New password' required)
-                    .settings-row
-                        label.col-sm-1.required Confirm:
-                        .col-sm-3
-                            input#user_confirm.form-control(type='password' ng-model='reset_info.confirm' ignite-match='reset_info.password' placeholder='Confirm new password' required ignite-on-enter='resetForm.$valid && resetPassword(user_info)')
-                    .settings-row
-                        button.btn.btn-primary(ng-disabled='resetForm.$invalid' ng-click='resetPassword(reset_info)') Reset Password
-
-include includes/footer

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/src/main/js/views/settings/admin.jade
----------------------------------------------------------------------
diff --git a/modules/web-console/src/main/js/views/settings/admin.jade b/modules/web-console/src/main/js/views/settings/admin.jade
deleted file mode 100644
index 862d959..0000000
--- a/modules/web-console/src/main/js/views/settings/admin.jade
+++ /dev/null
@@ -1,76 +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.
-
-.row(ng-controller='adminController')
-    .docs-content.greedy
-        .docs-header
-            h1 List of registered users
-            hr
-        .docs-body
-            .col-xs-12
-                table.table.table-striped.table-vertical-middle.admin(st-table='displayedUsers' st-safe-src='users')
-                    thead
-                        tr
-                            th.header(colspan='10')
-                                .col-xs-3
-                                    input.form-control(type='text' st-search='label' placeholder='Filter users...')
-                                .col-xs-9.admin-summary.text-right(colspan='10')
-                                    strong Total users: {{ users.length }}
-                                .col-xs-offset-6.col-xs-6.text-right
-                                    div(st-pagination st-items-by-page='15' st-displayed-pages='5' st-template='../templates/pagination.html')
-                        tr
-                            th(st-sort='userName') User
-                            th(st-sort='email') Email
-                            th(st-sort='company') Company
-                            th(st-sort='country') Country
-                            th.col-xs-2(st-sort='lastLogin' st-sort-default='reverse') Last login
-                            th.text-nowrap(st-sort='counters.clusters' st-descending-first bs-tooltip='"Clusters count"' data-placement='top')
-                                i.fa.fa-sitemap()
-                            th.text-nowrap(st-sort='counters.models' st-descending-first bs-tooltip='"Models count"' data-placement='top')
-                                i.fa.fa-object-group()
-                            th.text-nowrap(st-sort='counters.caches' st-descending-first bs-tooltip='"Caches count"' data-placement='top')
-                                i.fa.fa-database()
-                            th.text-nowrap(st-sort='counters.igfs' st-descending-first bs-tooltip='"IGFS count"' data-placement='top')
-                                i.fa.fa-folder-o()
-                            th(width='1%') Actions
-                    tbody
-                        tr(ng-repeat='row in displayedUsers track by row._id')
-                            td {{::row.userName}}
-                            td
-                                a(ng-href='mailto:{{::row.email}}') {{::row.email}}
-                            td {{::row.company}}
-                            td {{::row.countryCode}}
-                            td {{::row.lastLogin | date:'medium'}}
-                            td {{::row.counters.clusters}}
-                            td {{::row.counters.models}}
-                            td {{::row.counters.caches}}
-                            td {{::row.counters.igfs}}
-                            td.text-center
-                                a.btn.btn-default.dropdown-toggle(bs-dropdown='' ng-show='row._id != user._id' data-placement='bottom-right')
-                                    i.fa.fa-gear &nbsp;
-                                    span.caret
-                                ul.dropdown-menu(role='menu')
-                                    li
-                                        a(ng-click='becomeUser(row)') Become this user
-                                    li
-                                        a(ng-click='toggleAdmin(row)' ng-if='row.admin && row._id !== user._id') Revoke admin
-                                        a(ng-click='toggleAdmin(row)' ng-if='!row.admin && row._id !== user._id')  Grant admin
-                                    li
-                                        a(ng-click='removeUser(row)') Remove user
-                    tfoot
-                        tr
-                            td.text-right(colspan='10')
-                                div(st-pagination st-items-by-page='15' st-displayed-pages='5' st-template='../templates/pagination.html')

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/src/main/js/views/settings/profile.jade
----------------------------------------------------------------------
diff --git a/modules/web-console/src/main/js/views/settings/profile.jade b/modules/web-console/src/main/js/views/settings/profile.jade
deleted file mode 100644
index bc4965a..0000000
--- a/modules/web-console/src/main/js/views/settings/profile.jade
+++ /dev/null
@@ -1,76 +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.
-
-mixin lbl(txt)
-    label.col-sm-2.required.labelFormField #{txt}
-
-.row(ng-controller='profileController')
-    .docs-content.greedy
-        .docs-header
-            h1 User profile
-            hr
-        .docs-body
-            form.form-horizontal(name='profileForm' novalidate)
-                .col-sm-10(style='padding: 0')
-                    .details-row
-                        +lbl('First name:')
-                        .col-xs-5.col-sm-4
-                            input#profile-firstname.form-control(ignite-on-enter-focus-move='profile-lastname' type='text' ng-model='user.firstName' placeholder='Input first name' required ignite-auto-focus)
-                    .details-row
-                        +lbl('Last name:')
-                        .col-xs-5.col-sm-4
-                            input#profile-lastname.form-control(ignite-on-enter-focus-move='profile-email' type='text' ng-model='user.lastName' placeholder='Input last name' required)
-                    .details-row
-                        +lbl('Email:')
-                        .col-xs-5.col-sm-4
-                            input#profile-email.form-control(ignite-on-enter-focus-move='profile-company' type='email' ng-model='user.email' placeholder='Input email' required)
-                    .details-row
-                        +lbl('Company:')
-                        .col-xs-5.col-sm-4
-                            input#profile-company.form-control(ignite-on-enter-focus-move='profile-country' type='text' ng-model='user.company' placeholder='Input company name' required)
-                    .details-row
-                        +lbl('Country:')
-                        .col-xs-5.col-sm-4
-                            button#profile-country.select-toggle.form-control(bs-select bs-options='item.name as item.name for item in countries' type='text' ng-model='user.country' placeholder='Choose your country' ng-required='true')
-                    .details-row
-                        .advanced-options
-                            i.fa(
-                            ng-click='toggleToken()'
-                            ng-class='expandedToken ? "fa-chevron-circle-down" : "fa-chevron-circle-right"')
-                            a(ng-click='toggleToken()') {{expandedToken ? 'Cancel security token changing...' : 'Show security token...'}}
-                        div(ng-if='expandedToken')
-                            +lbl('Security token:')
-                            label {{user.token || 'No security token. Regenerate please.'}}
-                            i.tipLabel.fa.fa-refresh(ng-click='generateToken()' bs-tooltip='' data-title='Generate random security token')
-                            i.tipLabel.fa.fa-clipboard(ignite-copy-to-clipboard='{{user.token}}' bs-tooltip='' data-title='Copy security token to clipboard')
-                            i.tipLabel.fa.fa-question-circle(ng-if=lines bs-tooltip='' data-title='The security token is used for authorization of web agent')
-                    .details-row
-                        .advanced-options
-                            i.fa(
-                            ng-click='togglePassword()'
-                            ng-class='expandedPassword ? "fa-chevron-circle-down" : "fa-chevron-circle-right"')
-                            a(ng-click='togglePassword()') {{expandedPassword ? 'Cancel password changing...' : 'Change password...'}}
-                        div(ng-if='expandedPassword')
-                            .details-row
-                                +lbl('New password:')
-                                .col-xs-5.col-sm-4
-                                    input#profile_password.form-control(ignite-on-enter-focus-move='profile_confirm' type='password' ng-model='user.password' placeholder='New password')
-                            .details-row
-                                +lbl('Confirm:')
-                                .col-xs-5.col-sm-4
-                                    input#profile_confirm.form-control(type='password' ng-model='user.confirm' ignite-match='user.password' placeholder='Confirm new password')
-                .col-xs-12.col-sm-12.details-row
-                    a.btn.btn-primary(ng-disabled='!profileCouldBeSaved()' ng-click='profileCouldBeSaved() && saveUser()' bs-tooltip='' data-title='{{saveBtnTipText()}}' data-placement='bottom' data-trigger='hover') Save

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/src/main/js/views/signin.jade
----------------------------------------------------------------------
diff --git a/modules/web-console/src/main/js/views/signin.jade b/modules/web-console/src/main/js/views/signin.jade
deleted file mode 100644
index a6c64a8..0000000
--- a/modules/web-console/src/main/js/views/signin.jade
+++ /dev/null
@@ -1,163 +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.
-
-mixin lblRequired(txt)
-    label.col-xs-3.col-md-3.required #{txt}
-
-header#header.header
-    table.container
-        tr
-            td.col-xs-3.col-sm-3.col-md-2
-                ignite-header-logo
-            td
-                ignite-header-title
-
-.container.body-container
-    .main-content(ng-controller='auth')
-        .row.home
-            .signin-greedy
-                .col-xs-12.col-md-6
-                    form(name='form' novalidate)
-                        .modal-body.row(style='padding: 0 0 10px 0; margin: 0')
-                            .settings-row(ng-if='action == "signup"')
-                                h3.login-header Sign Up
-                            .settings-row(ng-if='action == "signin"')
-                                h3.login-header Sign In
-                            .settings-row(ng-if='action == "password/forgot"')
-                                h3.login-header Forgot password?
-                            .settings-row
-                                p.col-xs-12.col-md-11(ng-show='action == "password/forgot"')
-                                    | That's ok! Simply enter your email below and a reset password link will be sent to you via email. You can then follow that link and select a new password.
-                            .settings-row(ng-show='action == "signin"')
-                                +lblRequired('Email:')
-                                .col-xs-9.col-md-8
-                                    input#signin_email.form-control(ignite-on-enter-focus-move='user_password' type='email' ng-model='ui.email' placeholder='Input email' required)
-                            .settings-row(ng-show='action == "signup"')
-                                +lblRequired('Email:')
-                                .col-xs-9.col-md-8
-                                    input#signup_email.form-control(ignite-on-enter-focus-move='user_password' type='email' ng-model='ui.email' placeholder='Input email' required)
-                            .settings-row(ng-show='action != "password/forgot"')
-                                +lblRequired('Password:')
-                                .col-xs-9.col-md-8
-                                    input#user_password.form-control(ignite-on-enter-focus-move='user_confirm' type='password' ng-model='ui.password' placeholder='Password' ng-required='action != "password/forgot"' ignite-on-enter='action == "signin" && form.$valid && auth(action, ui)')
-                            .settings-row(ng-if='action == "signup"')
-                                +lblRequired('Confirm:')
-                                .col-xs-9.col-md-8
-                                    input#user_confirm.form-control(ignite-on-enter-focus-move='first_name' type='password' ng-model='ui_exclude.confirm' ignite-match='ui.password' placeholder='Confirm password' ng-required='action == "signup"')
-                            .settings-row(ng-show='action == "signup"')
-                                +lblRequired('First Name:')
-                                .col-xs-9.col-md-8
-                                    input#first_name.form-control(ignite-on-enter-focus-move='last_name' type='text' ng-model='ui.firstName' placeholder='Input first name' ng-required='action=="signup"')
-                            .settings-row(ng-show='action == "signup"')
-                                +lblRequired('Last Name:')
-                                .col-xs-9.col-md-8
-                                    input#last_name.form-control(ignite-on-enter-focus-move='company' type='text' ng-model='ui.lastName' placeholder='Input last name' ng-required='action=="signup"')
-                            .settings-row(ng-show='action == "password/forgot"')
-                                +lblRequired('Email:')
-                                .col-xs-9.col-md-8
-                                    input#forgot_email.form-control(ignite-on-enter='form.$valid && forgotPassword(ui)' type='email' ng-model='ui.email' placeholder='Input email' required)
-                            .settings-row(ng-show='action == "signup"')
-                                +lblRequired('Company:')
-                                .col-xs-9.col-md-8
-                                    input#company.form-control(ignite-on-enter-focus-move='country' type='text' ng-model='ui.company' placeholder='Input company name' ng-required='action=="signup"')
-                            .settings-row(ng-show='action == "signup"')
-                                +lblRequired('Country:')
-                                .col-xs-9.col-md-8
-                                    button#country.select-toggle.form-control(ignite-on-enter-focus-move='signup' bs-select bs-options='item.name as item.name for item in countries' type='text' ng-model='ui.country' placeholder='Choose your country' ng-required='action=="signup"')
-                            .settings-row(ignite-terms)
-                                .col-md-offset-3(ng-if='action == "signup" && terms.termsState')
-                                    label
-                                        input(type='checkbox' ng-model='ui_exclude.agree', ng-required='true')
-                                        | I agree to the #[a(ui-sref='{{::terms.termsState}}' target='_blank') terms and conditions]
-                        .col-xs-12.col-md-11
-                            .login-footer(ng-show='action == "signup"')
-                                a.labelField(ng-click='action = "password/forgot"' ignite-on-click-focus='signin_email') Forgot password?
-                                a.labelLogin(ng-click='action = "signin"' ignite-on-click-focus='signin_email') Sign In
-                                button#signup.btn.btn-primary(ng-click='auth(action, ui)' ng-disabled='form.$invalid') Sign Up
-                        .col-xs-12.col-md-11
-                            .login-footer(ng-show='action == "password/forgot"')
-                                a.labelField(ng-click='action = "signin"' ignite-on-click-focus='signin_email') Sign In
-                                button#forgot.btn.btn-primary(ng-click='forgotPassword(ui)' ng-disabled='form.$invalid') Send it to me
-                        .col-xs-12.col-md-11
-                            .login-footer(ng-show='action == "signin"')
-                                a.labelField(ng-click='action = "password/forgot"' ignite-on-click-focus='signin_email') Forgot password?
-                                a.labelLogin(ng-click='action = "signup"' ignite-on-click-focus='first_name') Sign Up
-                                button#login.btn.btn-primary(ng-click='auth(action, ui)' ng-disabled='form.$invalid') Sign In
-
-                    .col-xs-12.col-md-11.home-panel
-                        ignite-features
-                .col-xs-12.col-md-6
-                    #carousel.carousel.slide
-                        // Indicators
-                        ol.carousel-indicators
-                            li.active(data-target='#carousel', data-slide-to='0')
-                            li(data-target='#carousel', data-slide-to='1')
-                            li(data-target='#carousel', data-slide-to='2')
-                            li(data-target='#carousel', data-slide-to='3')
-                            li(data-target='#carousel', data-slide-to='4')
-                            li(data-target='#carousel', data-slide-to='5')
-                            li(data-target='#carousel', data-slide-to='6')
-                        // Wrapper for slides
-                        .carousel-inner(role='listbox')
-                            .item.active
-                                img(src='/images/cluster.png', alt='Clusters screen')
-                                .carousel-caption
-                                    h3 Clusters screen
-                                    p Configure clusters, link clusters to caches
-                            .item
-                                img(src='/images/cache.png', alt='Caches screen')
-                                .carousel-caption
-                                    h3 Caches screen
-                                    p Configure caches, link domain models to caches, link caches to clusters
-                            .item
-                                img(src='/images/domains.png', alt='Domain model screen')
-                                .carousel-caption
-                                    h3 Domain model screen
-                                    p Manually enter domain model or import from database
-                            .item
-                                img(src='/images/summary.png', alt='Summary screen')
-                                .carousel-caption
-                                    h3 Summary screen
-                                    p Preview XML config, JAVA code,Docker file and download project
-                            .item
-                                img(src='/images/query-table.png', alt='Query')
-                                .carousel-caption
-                                    h3 Query
-                                    p Explain SQL, execute, scan queries
-                            .item
-                                img(src='/images/query-metadata.png', alt='Cache metadata')
-                                .carousel-caption
-                                    h3 Cache metadata
-                                    p View cache type metadata
-                            .item
-                                img(src='/images/query-chart.png', alt='Query chart')
-                                .carousel-caption
-                                    h3 Query chart
-                                    p View data in tabular form and as charts
-                        // Controls
-                        a.left.carousel-control(href='#carousel', ng-click='$event.preventDefault()', role='button', data-slide='prev')
-                            span.fa.fa-chevron-left(aria-hidden='true')
-                            span.sr-only Previous
-                        a.right.carousel-control(href='#carousel', ng-click='$event.preventDefault()', role='button', data-slide='next')
-                            span.fa.fa-chevron-right(aria-hidden='true')
-                            span.sr-only Next
-
-include includes/footer
-
-script.
-    $('.carousel').carousel()
-
-

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/src/main/js/views/sql/cache-metadata.jade
----------------------------------------------------------------------
diff --git a/modules/web-console/src/main/js/views/sql/cache-metadata.jade b/modules/web-console/src/main/js/views/sql/cache-metadata.jade
deleted file mode 100644
index 450c178..0000000
--- a/modules/web-console/src/main/js/views/sql/cache-metadata.jade
+++ /dev/null
@@ -1,40 +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.
-.popover.cache-metadata(tabindex='-1' ignite-loading='loadingCacheMetadata' ignite-loading-text='Loading metadata...' ng-init='importMetadata()')
-    h3.popover-title
-        label.labelField Metadata for caches:
-        button.close(id='cache-metadata-close' ng-click='$hide()') &times;
-        .input-tip
-            input.form-control(type='text' ng-model='metaFilter' placeholder='Filter metadata...')
-    .popover-content(ng-if='metadata && metadata.length > 0')
-        treecontrol.tree-classic(tree-model='metadata' options='metaOptions' filter-expression='metaFilter')
-            span(ng-switch='' on='node.type')
-                span(ng-switch-when='type' ng-dblclick='dblclickMetadata(paragraph, node)')
-                    i.fa.fa-table
-                    label.clickable(ng-bind='node.displayName')
-                span(ng-switch-when='plain')
-                    label {{node.name}}
-                span(ng-switch-when='field' ng-dblclick='dblclickMetadata(paragraph, node)')
-                    i.fa(ng-class='node.system ? "fa-file-text-o" : "fa-file-o"')
-                    label.clickable {{node.name}} [{{node.clazz}}]
-                label(ng-switch-when='indexes') {{node.name}}
-                label(ng-switch-when='index') {{node.name}}
-                span(ng-switch-when='index-field' ng-dblclick='dblclickMetadata(paragraph, node)')
-                    i.fa(ng-class='node.order ? "fa-sort-amount-desc" : "fa-sort-amount-asc"')
-                    label.clickable {{node.name}}
-    .popover-content(ng-if='!metadata || metadata.length == 0')
-        label.content-empty No types found
-    h3.popover-footer Double click to paste into editor

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/src/main/js/views/sql/chart-settings.jade
----------------------------------------------------------------------
diff --git a/modules/web-console/src/main/js/views/sql/chart-settings.jade b/modules/web-console/src/main/js/views/sql/chart-settings.jade
deleted file mode 100644
index 5a1ceed..0000000
--- a/modules/web-console/src/main/js/views/sql/chart-settings.jade
+++ /dev/null
@@ -1,40 +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.
-
-.popover.settings(tabindex='-1' style='width: 300px')
-    .arrow
-    h3.popover-title(style='color: black') Chart settings
-    button.close(id='chart-settings-close' ng-click='$hide()') &times;
-    .popover-content
-        form.form-horizontal.chart-settings(name='chartSettingsForm' novalidate)
-            .form-group.chart-settings
-                -var btnClass = 'col.value < 0 ? "btn-success" : "btn-default"'
-
-                label All columns (drag columns to axis)
-                ul.chart-settings-columns-list(dnd-list='paragraph.chartColumns' dnd-allowed-types='[]')
-                    li(ng-repeat='col in paragraph.chartColumns track by $index')
-                        .btn.btn-default.btn-chart-column-movable(ng-class=btnClass dnd-draggable='col' dnd-effect-allowed='copy') {{col.label}}
-                label X axis (accept only one column)
-                ul.chart-settings-columns-list(dnd-list='paragraph.chartKeyCols' dnd-drop='chartAcceptKeyColumn(paragraph, item)')
-                    li(ng-repeat='col in paragraph.chartKeyCols track by $index')
-                        .btn.btn-default.btn-chart-column(ng-class=btnClass) {{col.label}}
-                            i.fa.fa-close(ng-click='chartRemoveKeyColumn(paragraph, $index)')
-                label Y axis (accept only numeric columns)
-                ul.chart-settings-columns-list(dnd-list='paragraph.chartValCols' dnd-drop='chartAcceptValColumn(paragraph, item)')
-                    li(ng-repeat='col in paragraph.chartValCols track by $index')
-                        .btn.btn-default.btn-chart-column(ng-style='chartColor($index)') {{col.label}}
-                            button.btn-chart-column-agg-fx.select-toggle(ng-change='applyChartSettings(paragraph)' ng-show='paragraphTimeSpanVisible(paragraph)' ng-style='chartColor($index)' ng-model='col.aggFx' placeholder='...' bs-select bs-options='item for item in aggregateFxs' data-container='false' tabindex='-1')
-                            i.fa.fa-close(ng-click='chartRemoveValColumn(paragraph, $index)')

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/src/main/js/views/sql/notebook-new.jade
----------------------------------------------------------------------
diff --git a/modules/web-console/src/main/js/views/sql/notebook-new.jade b/modules/web-console/src/main/js/views/sql/notebook-new.jade
deleted file mode 100644
index 51200e8..0000000
--- a/modules/web-console/src/main/js/views/sql/notebook-new.jade
+++ /dev/null
@@ -1,31 +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.
-
-.modal(tabindex='-1' role='dialog')
-    .modal-dialog
-        .modal-content
-            .modal-header
-                button.close(ng-click='$hide()') &times;
-                h4.modal-title New SQL notebook
-            form.form-horizontal.modal-body.row(name='ui.inputForm' novalidate)
-                div
-                    .col-sm-2
-                        label.required.labelFormField Name:&nbsp;
-                    .col-sm-10
-                        input.form-control(id='create-notebook' type='text' ng-model='name' required ignite-on-enter='ui.inputForm.$valid && createNewNotebook(name)' ignite-auto-focus)
-            .modal-footer
-                button.btn.btn-default(id='copy-btn-cancel' ng-click='$hide()') Cancel
-                button.btn.btn-primary(id='copy-btn-confirm' ng-disabled='ui.inputForm.$invalid' ng-click='createNewNotebook(name)') Create

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/src/main/js/views/sql/paragraph-rate.jade
----------------------------------------------------------------------
diff --git a/modules/web-console/src/main/js/views/sql/paragraph-rate.jade b/modules/web-console/src/main/js/views/sql/paragraph-rate.jade
deleted file mode 100644
index 03c6497..0000000
--- a/modules/web-console/src/main/js/views/sql/paragraph-rate.jade
+++ /dev/null
@@ -1,31 +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.
-
-.popover.settings(tabindex='-1' style='width: 200px')
-    .arrow
-    h3.popover-title(style='color: black') Refresh rate
-    button.close(id='paragraph-rate-close' ng-click='$hide()') &times;
-    .popover-content
-        form(name='popoverForm' novalidate)
-            .form-group(style='padding: 5px')
-                .col-sm-4
-                    input.form-control(id='paragraph-rate' ng-init='value = paragraph.rate.value' ng-model='value' type='number' min='1' required ignite-auto-focus)
-                .col-sm-8(style='padding-left: 5px')
-                    button.form-control.select-toggle(id='paragraph-unit' ng-init='unit = paragraph.rate.unit' ng-model='unit' required placeholder='Time unit' bs-select bs-options='item.value as item.label for item in timeUnit' data-container='false' tabindex='0')
-            .form-actions(style='margin-top: 30px; padding: 5px')
-                button.btn.btn-primary(id='paragraph-rate-start' ng-disabled='popoverForm.$invalid' ng-click='startRefresh(paragraph, value, unit); $hide()') Start
-                button.btn.btn-primary.btn-default(id='paragraph-rate-stop' ng-click='stopRefresh(paragraph); $hide()' ng-disabled='!paragraph.rate.installed') Stop
-

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/src/main/js/views/sql/sql.jade
----------------------------------------------------------------------
diff --git a/modules/web-console/src/main/js/views/sql/sql.jade b/modules/web-console/src/main/js/views/sql/sql.jade
deleted file mode 100644
index a5e7fae..0000000
--- a/modules/web-console/src/main/js/views/sql/sql.jade
+++ /dev/null
@@ -1,201 +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.
-
-mixin btn-toolbar(btn, click, tip, focusId)
-    i.btn.btn-default.fa(class=btn ng-click=click bs-tooltip='' data-title=tip ignite-on-click-focus=focusId data-trigger='hover' data-placement='bottom')
-
-mixin btn-toolbar-data(btn, kind, tip)
-    i.btn.btn-default.fa(class=btn ng-click='setResult(paragraph, "#{kind}")' ng-class='{active: resultEq(paragraph, "#{kind}")}' bs-tooltip='' data-title=tip data-trigger='hover' data-placement='bottom')
-
-mixin result-toolbar
-    .btn-group(ng-model='paragraph.result' ng-click='$event.stopPropagation()' style='left: 50%; margin: 0 0 0 -70px;display: block;')
-        +btn-toolbar-data('fa-table', 'table', 'Show data in tabular form')
-        +btn-toolbar-data('fa-bar-chart', 'bar', 'Show bar chart<br/>By default first column - X values, second column - Y values<br/>In case of one column it will be treated as Y values')
-        +btn-toolbar-data('fa-pie-chart', 'pie', 'Show pie chart<br/>By default first column - pie labels, second column - pie values<br/>In case of one column it will be treated as pie values')
-        +btn-toolbar-data('fa-line-chart', 'line', 'Show line chart<br/>By default first column - X values, second column - Y values<br/>In case of one column it will be treated as Y values')
-        +btn-toolbar-data('fa-area-chart', 'area', 'Show area chart<br/>By default first column - X values, second column - Y values<br/>In case of one column it will be treated as Y values')
-
-mixin chart-settings(mdl)
-    .row
-        .col-xs-4
-            .chart-settings-link(ng-show='paragraph.chart && paragraph.chartColumns.length > 0')
-                a(title='Click to show chart settings dialog' ng-click='$event.stopPropagation()' bs-popover data-template-url='/sql/chart-settings.html' data-placement='bottom' data-auto-close='1' data-trigger='click')
-                    i.fa.fa-bars
-                    | Chart settings
-                div(ng-show='paragraphTimeSpanVisible(paragraph)')
-                    label Show
-                    button.select-manual-caret.btn.btn-default(ng-model='paragraph.timeLineSpan' ng-change='applyChartSettings(paragraph)' bs-options='item for item in timeLineSpans' bs-select data-caret-html='<span class="caret"></span>')
-                    label min
-        .col-xs-4
-            +result-toolbar
-
-mixin notebook-rename
-    .docs-header.notebook-header
-        h1.col-sm-6(ng-hide='notebook.edit')
-            label(style='max-width: calc(100% - 60px)') {{notebook.name}}
-            .btn-group(ng-if='!demo')
-                +btn-toolbar('fa-pencil', 'notebook.edit = true;notebook.editName = notebook.name', 'Rename notebook')
-                +btn-toolbar('fa-trash', 'removeNotebook()', 'Remove notebook')
-        h1.col-sm-6(ng-show='notebook.edit')
-            i.btn.fa.fa-floppy-o(ng-show='notebook.editName' ng-click='renameNotebook(notebook.editName)' bs-tooltip data-title='Save notebook name' data-trigger='hover')
-            .input-tip
-                input.form-control(ng-model='notebook.editName' required ignite-on-enter='renameNotebook(notebook.editName)' ignite-on-escape='notebook.edit = false;')
-        h1.pull-right
-            a.dropdown-toggle(data-toggle='dropdown' bs-dropdown='scrollParagraphs' data-placement='bottom-right') Scroll to query
-                span.caret
-            .btn-group(style='margin-top: 2px')
-                +btn-toolbar('fa-plus', 'addParagraph()', 'Add new query')
-
-mixin notebook-error
-    h2 Failed to load notebook
-    label.col-sm-12 Notebook not accessible any more. Go back to configuration or open to another notebook.
-    button.h3.btn.btn-primary(ui-sref='base.configuration.clusters') Back to configuration
-
-mixin paragraph-rename
-    .col-sm-6(ng-hide='paragraph.edit')
-        i.tipLabel.fa(ng-class='paragraphExpanded(paragraph) ? "fa-chevron-circle-down" : "fa-chevron-circle-right"')
-        label {{paragraph.name}}
-
-        .btn-group(ng-hide='notebook.paragraphs.length > 1')
-            +btn-toolbar('fa-pencil', 'paragraph.edit = true; paragraph.editName = paragraph.name; $event.stopPropagation();', 'Rename query', 'paragraph-name-{{paragraph.id}}')
-
-        .btn-group(ng-show='notebook.paragraphs.length > 1' ng-click='$event.stopPropagation();')
-            +btn-toolbar('fa-pencil', 'paragraph.edit = true; paragraph.editName = paragraph.name;', 'Rename query', 'paragraph-name-{{paragraph.id}}')
-            +btn-toolbar('fa-remove', 'removeParagraph(paragraph)', 'Remove query')
-
-    .col-sm-6(ng-show='paragraph.edit')
-        i.tipLabel.fa(style='float: left;' ng-class='paragraphExpanded(paragraph) ? "fa-chevron-circle-down" : "fa-chevron-circle-right"')
-        i.tipLabel.fa.fa-floppy-o(style='float: right;' ng-show='paragraph.editName' ng-click='renameParagraph(paragraph, paragraph.editName); $event.stopPropagation();' bs-tooltip data-title='Save query name' data-trigger='hover')
-        .input-tip
-            input.form-control(id='paragraph-name-{{paragraph.id}}' ng-model='paragraph.editName' required ng-click='$event.stopPropagation();' ignite-on-enter='renameParagraph(paragraph, paragraph.editName)' ignite-on-escape='paragraph.edit = false')
-
-mixin query-controls
-    .sql-controls
-        a.btn.btn-primary(ng-disabled='!actionAvailable(paragraph, true)' ng-click='actionAvailable(paragraph, true) && execute(paragraph)' data-placement='bottom' bs-tooltip data-title='{{actionTooltip(paragraph, "execute", true)}}') Execute
-        a.btn.btn-primary(ng-disabled='!actionAvailable(paragraph, true)' ng-click='actionAvailable(paragraph, true) && explain(paragraph)' data-placement='bottom' bs-tooltip data-title='{{actionTooltip(paragraph, "explain", true)}}') Explain
-        a.btn.btn-primary(ng-disabled='!actionAvailable(paragraph, false)' ng-click='actionAvailable(paragraph, false) && scan(paragraph)' data-placement='bottom' bs-tooltip data-title='{{actionTooltip(paragraph, "execute scan", false)}}') Scan
-        .pull-right
-            labelHide System columns:
-            a.btn.btn-default.fa.fa-bars.tipLabel(ng-class='{"btn-info": paragraph.systemColumns}' ng-click='toggleSystemColumns(paragraph)' ng-disabled='paragraph.disabledSystemColumns' bs-tooltip data-title='Show "_KEY", "_VAL" columns')
-            label.tipLabel Refresh rate:
-            button.btn.btn-default.fa.fa-clock-o.tipLabel(title='Click to show refresh rate dialog' ng-class='{"btn-info": paragraph.rate && paragraph.rate.installed}' bs-popover data-template-url='/sql/paragraph-rate.html' data-placement='left' data-auto-close='1' data-trigger='click') {{rateAsString(paragraph)}}
-            label.tipLabel Page size:
-            button.select-toggle.fieldButton.btn.btn-default(ng-model='paragraph.pageSize' bs-options='item for item in pageSizes' bs-select bs-tooltip data-placement='bottom-right' data-title='Max number of rows to show in query result as one page')
-
-mixin table-result
-    .sql-table-total.row
-        .col-xs-4
-            label(style='margin-right: 10px;') Page: #[b {{paragraph.page}}]
-            label Results so far: #[b {{paragraph.rows.length + paragraph.total}}]
-        .col-xs-4
-            +result-toolbar
-        .col-xs-4
-            .btn-group.pull-right(ng-disabled='paragraph.loading')
-                button.btn.btn-primary.fieldButton(ng-click='exportCsv(paragraph)' bs-tooltip data-title='{{actionTooltip(paragraph, "export", false)}}') Export
-                button.btn.btn-primary(id='export-item-dropdown' data-toggle='dropdown' data-container='body' bs-dropdown='exportDropdown' data-placement='bottom-right')
-                    span.caret
-    .grid(ui-grid='paragraph.gridOptions' ui-grid-resize-columns ui-grid-exporter)
-
-mixin chart-result
-    div(ng-show='paragraph.queryExecuted()')
-        +chart-settings
-        div(ng-show='paragraph.chartColumns.length > 0 && !paragraph.chartColumnsConfigured()')
-            .sql-empty-result Cannot display chart. Please configure axis using #[b Chart settings]
-        div(ng-show='paragraph.chartColumns.length == 0')
-            .sql-empty-result Cannot display chart. Result set must contain Java build-in type columns. Please change query and execute it again.
-        div(ng-show='paragraph.chartColumnsConfigured()')
-            div(ng-show='paragraph.timeLineSupported() || !paragraph.chartTimeLineEnabled()')
-                div(ng-repeat='chart in paragraph.charts')
-                    nvd3(options='chart.options' data='chart.data' api='chart.api')
-            .sql-empty-result(ng-show='!paragraph.timeLineSupported() && paragraph.chartTimeLineEnabled()') Pie chart does not support 'TIME_LINE' column for X-axis. Please use another column for X-axis or switch to another chart.
-    .sql-empty-result(ng-hide='paragraph.queryExecuted()')
-        .row
-            .col-xs-4.col-xs-offset-4
-                +result-toolbar
-        label.margin-top-dflt Charts do not support #[b Explain] and #[b Scan] query
-
-mixin footer-controls
-    hr(style='margin-top: 0; margin-bottom: 5px')
-    a(style='float: left; margin-left: 10px; margin-bottom: 5px' ng-click='showResultQuery(paragraph)') Show query
-
-    -var nextVisibleCondition = 'paragraph.queryId && (paragraph.table() || paragraph.chart() && (paragraph.timeLineSupported() || !paragraph.chartTimeLineEnabled()))'
-
-    .sql-next(ng-show=nextVisibleCondition)
-        i.fa.fa-chevron-circle-right(ng-class='{disabled: paragraph.loading}' ng-click='!paragraph.loading && nextPage(paragraph)')
-        a(ng-class='{disabled: paragraph.loading}' ng-click='!paragraph.loading && nextPage(paragraph)') Next
-
-.row(ng-controller='sqlController')
-    .docs-content
-        .row(ng-if='notebook' bs-affix style='margin-bottom: 20px;')
-            +notebook-rename
-
-        ignite-information(data-title='With SQL notebook you can' style='margin-top: 0; margin-bottom: 30px')
-            ul
-                li Create any number of queries
-                li Execute and explain SQL queries
-                li Execute scan queries
-                li View data in tabular form and as charts
-
-        div(ng-if='notebookLoadFailed' style='text-align: center')
-            +notebook-error
-
-        div(ng-if='notebook' ignite-loading='sqlLoading' ignite-loading-text='{{ loadingText }}' ignite-loading-position='top')
-            .docs-body.paragraphs
-                .panel-group(bs-collapse ng-model='notebook.expandedParagraphs' data-allow-multiple='true' data-start-collapsed='false')
-                    .panel.panel-default(ng-repeat='paragraph in notebook.paragraphs')
-                        .panel-heading(id='{{paragraph.id}}' bs-collapse-toggle)
-                            .row
-                                +paragraph-rename
-                        .panel-collapse(role='tabpanel' bs-collapse-target)
-                            .col-sm-12
-                                .col-xs-8.col-sm-9(style='border-right: 1px solid #eee')
-                                    .sql-editor(ignite-ace='{onLoad: aceInit(paragraph), theme: "chrome", mode: "sql", require: ["ace/ext/language_tools"],' +
-                                    'advanced: {enableSnippets: false, enableBasicAutocompletion: true, enableLiveAutocompletion: true}}'
-                                    ng-model='paragraph.query')
-                                .col-xs-4.col-sm-3
-                                    div(ng-show='caches.length > 0' style='padding: 5px 10px' st-table='displayedCaches' st-safe-src='caches')
-                                        lable.labelField.labelFormField Caches:
-                                        i.fa.fa-database.tipField(title='Click to show cache types metadata dialog' bs-popover data-template-url='/sql/cache-metadata.html', data-placement='bottom', data-trigger='click')
-                                        .input-tip
-                                            input.form-control(type='text' st-search='label' placeholder='Filter caches...')
-                                        table.links
-                                            tbody.scrollable-y(style='max-height: 15em; display: block;')
-                                                tr(ng-repeat='cache in displayedCaches track by cache.name')
-                                                    td(style='width: 100%')
-                                                        input.labelField(id='cache{{$index}}' type='radio' value='{{cache.name}}' ng-model='paragraph.cacheName')
-                                                        label(for='cache{{$index}}' ng-bind='cache.label')
-                                    .empty-caches(ng-show='displayedCaches.length == 0 && caches.length != 0')
-                                        label Wrong caches filter
-                                    .empty-caches(ng-show='caches.length == 0')
-                                        label No caches
-                            .col-sm-12
-                                hr(style='margin: 0')
-                            .col-sm-12
-                                +query-controls
-                            .col-sm-12.sql-error-result(ng-show='paragraph.errMsg') Error: {{paragraph.errMsg}}
-                            .col-sm-12(ng-show='!paragraph.errMsg && paragraph.queryArgs')
-                                hr(style='margin-top: 0; margin-bottom: 10px')
-
-                                .sql-empty-result(ng-show='!paragraph.nonEmpty()') Result set is empty
-
-                                div(ng-show='paragraph.table() && paragraph.nonEmpty()')
-                                    +table-result
-
-                                div(ng-show='paragraph.chart() && paragraph.nonEmpty()')
-                                    +chart-result
-
-                                div(ng-show='!paragraph.refreshExecuting()')
-                                    +footer-controls

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/src/main/js/views/templates/agent-download.jade
----------------------------------------------------------------------
diff --git a/modules/web-console/src/main/js/views/templates/agent-download.jade b/modules/web-console/src/main/js/views/templates/agent-download.jade
deleted file mode 100644
index 864694b..0000000
--- a/modules/web-console/src/main/js/views/templates/agent-download.jade
+++ /dev/null
@@ -1,48 +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.
-
-.modal.center(tabindex='-1' role='dialog')
-    .modal-dialog
-        .modal-content
-            #errors-container.modal-header.header
-                h4.modal-title(ng-if='!hasAgents') Connection to Ignite Web Agent is not established
-                h4.modal-title(ng-if='hasAgents') Connection to Ignite Node is not established
-            .agent-download(ng-if='!hasAgents')
-                p Please download and run #[a(href='javascript:void(0)' ng-click='downloadAgent()') ignite-web-agent] in order to {{::agentGoal}}
-                p For run:
-                ul
-                    li Download and unzip #[a(href='javascript:void(0)' ng-click='downloadAgent()') ignite-web-agent] archive
-                    li Run shell file #[b ignite-web-agent.{sh|bat}]
-                p Refer to #[b README.txt] in agent folder for more information
-                .modal-advanced-options
-                    i.fa.fa-chevron-circle-down(ng-show='agentLoad.showToken' ng-click='agentLoad.showToken = ! agentLoad.showToken')
-                    i.fa.fa-chevron-circle-right(ng-show='!agentLoad.showToken' ng-click='agentLoad.showToken = ! agentLoad.showToken')
-                    a(ng-click='agentLoad.showToken = ! agentLoad.showToken') {{agentLoad.showToken ? 'Hide security token...' : 'Show security token...'}}
-                .details-row(ng-show='agentLoad.showToken')
-                    label.labelField Security token: {{user.token}}
-                    i.tipLabel.fa.fa-clipboard(ignite-copy-to-clipboard='{{user.token}}' bs-tooltip='' data-title='Copy security token to clipboard')
-                    i.tipLabel.fa.fa-question-circle(ng-if=lines bs-tooltip='' data-title='The security token is used for authorization of web agent')
-            .agent-download(ng-if='hasAgents')
-                p Connection to Ignite Web Agent is established, but agent failed to connect to Ignite Node
-                p Please check the following:
-                ul
-                    li Ignite Grid is up and running
-                    li In agent settings check URI for connect to Ignite REST server
-                    li Check agent logs for errors
-                    li Refer to #[b README.txt] in agent folder for more information
-            .modal-footer
-                button.btn.btn-default(ng-click='back()') {{::backText}}
-                button.btn.btn-primary(ng-if='!hasAgents' ng-click='downloadAgent()') Download agent

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/src/main/js/views/templates/alert.jade
----------------------------------------------------------------------
diff --git a/modules/web-console/src/main/js/views/templates/alert.jade b/modules/web-console/src/main/js/views/templates/alert.jade
deleted file mode 100644
index 0ab3dd9..0000000
--- a/modules/web-console/src/main/js/views/templates/alert.jade
+++ /dev/null
@@ -1,21 +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.
-
-.alert(ng-show='type' ng-class='[type ? "alert-" + type : null]')
-    button.close(type='button', ng-if='dismissable', ng-click='$hide()') &times;
-    i.alert-icon.fa(ng-if='icon' ng-class='[icon]')
-    span.alert-title(ng-bind='title')
-    span.alert-content(ng-bind-html='content')

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/src/main/js/views/templates/batch-confirm.jade
----------------------------------------------------------------------
diff --git a/modules/web-console/src/main/js/views/templates/batch-confirm.jade b/modules/web-console/src/main/js/views/templates/batch-confirm.jade
deleted file mode 100644
index 7451314..0000000
--- a/modules/web-console/src/main/js/views/templates/batch-confirm.jade
+++ /dev/null
@@ -1,32 +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.
-
-.modal(tabindex='-1' role='dialog')
-    .modal-dialog
-        .modal-content
-            .modal-header
-                button.close(ng-click='cancel()' aria-hidden='true') &times;
-                h4.modal-title Confirmation
-            .modal-body(ng-show='content')
-                p(ng-bind-html='content' style='text-align: center')
-            .modal-footer
-                .checkbox.labelField
-                    label
-                        input(type='checkbox' ng-model='applyToAll')
-                        | Apply to all
-                button.btn.btn-default(id='batch-confirm-btn-cancel' ng-click='cancel()') Cancel
-                button.btn.btn-default(id='batch-confirm-btn-skip' ng-click='skip(applyToAll)') Skip
-                button.btn.btn-primary(id='batch-confirm-btn-overwrite' ng-click='overwrite(applyToAll)') Overwrite

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/src/main/js/views/templates/clone.jade
----------------------------------------------------------------------
diff --git a/modules/web-console/src/main/js/views/templates/clone.jade b/modules/web-console/src/main/js/views/templates/clone.jade
deleted file mode 100644
index 25e99e7..0000000
--- a/modules/web-console/src/main/js/views/templates/clone.jade
+++ /dev/null
@@ -1,31 +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.
-
-.modal(tabindex='-1' role='dialog')
-    .modal-dialog
-        .modal-content
-            .modal-header
-                button.close(ng-click='$hide()') &times;
-                h4.modal-title Clone
-            form.form-horizontal.modal-body.row(name='ui.inputForm' novalidate)
-                div
-                    .col-sm-2
-                        label.required.labelFormField New name:&nbsp;
-                    .col-sm-10
-                        input.form-control(id='copy-new-name' type='text' ng-model='newName' ignite-on-enter='form.$valid && ok(newName)' required ignite-auto-focus)
-            .modal-footer
-                button.btn.btn-default(id='copy-btn-cancel' ng-click='$hide()') Cancel
-                button.btn.btn-primary(id='copy-btn-confirm' ng-disabled='ui.inputForm.$invalid' ng-click='ok(newName)') Confirm

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/src/main/js/views/templates/confirm.jade
----------------------------------------------------------------------
diff --git a/modules/web-console/src/main/js/views/templates/confirm.jade b/modules/web-console/src/main/js/views/templates/confirm.jade
deleted file mode 100644
index 26af061..0000000
--- a/modules/web-console/src/main/js/views/templates/confirm.jade
+++ /dev/null
@@ -1,31 +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.
-
-.modal(tabindex='-1' role='dialog')
-    .modal-dialog
-        .modal-content
-            .modal-header
-                button.close(ng-click='confirmCancel()' aria-hidden='true') &times;
-                h4.modal-title Confirmation
-            .modal-body(ng-show='content')
-                p(ng-bind-html='content' style='text-align: center;')
-            .modal-footer
-                button#confirm-btn-cancel.btn.btn-default(ng-click='confirmCancel()') Cancel
-
-                button#confirm-btn-no.btn.btn-default(ng-if='yesNo' ng-click='confirmNo()') No
-                button#confirm-btn-yes.btn.btn-primary(ng-if='yesNo' ng-click='confirmYes()') Yes
-
-                button#confirm-btn-ok.btn.btn-primary(ng-if='!yesNo' ng-click='confirmYes()') Confirm

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/src/main/js/views/templates/demo-info.jade
----------------------------------------------------------------------
diff --git a/modules/web-console/src/main/js/views/templates/demo-info.jade b/modules/web-console/src/main/js/views/templates/demo-info.jade
deleted file mode 100644
index 100e806..0000000
--- a/modules/web-console/src/main/js/views/templates/demo-info.jade
+++ /dev/null
@@ -1,45 +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.
-
-.modal.center(role='dialog')
-    .modal-dialog
-        .modal-content
-            #errors-container.modal-header.header
-                button.close(ng-click='close()' aria-hidden='true') &times;
-                h4.modal-title {{title}}
-            .modal-body
-                div(ng-bind-html='message')
-                div(ng-hide='hasAgents')
-                    p &nbsp;
-                    div
-                        h4
-                            i.fa.fa-download.fa-cursor-default
-                            | &nbsp;How To Start Demo
-                        ul
-                            li
-                                a(ng-click='downloadAgent()') #[b Download]
-                                | &nbsp; and unzip ignite-web-agent archive
-                            li #[b Run] shell file ignite-web-agent.{sh|bat}
-                div(ng-show='hasAgents')
-                    h4
-                        i.fa.fa-star-o.fa-cursor-default
-                        | &nbsp;Start Demo
-                    ul
-                        li Web Agent is already started
-                        li Close dialog and try Web Console
-            .modal-footer
-                button.btn.btn-default(ng-class='hasAgents ? "btn-primary" : "btn-default"' ng-click='close()') Close
-                button.btn.btn-primary(ng-hide='hasAgents' ng-click='downloadAgent()') Download agent

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/src/main/js/views/templates/dropdown.jade
----------------------------------------------------------------------
diff --git a/modules/web-console/src/main/js/views/templates/dropdown.jade b/modules/web-console/src/main/js/views/templates/dropdown.jade
deleted file mode 100644
index 96cc43d..0000000
--- a/modules/web-console/src/main/js/views/templates/dropdown.jade
+++ /dev/null
@@ -1,21 +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.
-
-ul.dropdown-menu(tabindex='-1' role='menu' ng-show='content && content.length')
-    li(role='presentation' ui-sref-active='active' ng-class='{divider: item.divider, active: item.active, custom: item.custom}' ng-repeat='item in content')
-        a(role='menuitem' tabindex='-1' ui-sref='{{item.sref}}' ng-if='!item.divider && item.sref' ng-bind='item.text')
-        a(role='menuitem' tabindex='-1' ng-href='{{item.href}}' ng-if='!item.divider && item.href' target='{{item.target || ""}}' ng-bind='item.text')
-        a(role='menuitem' tabindex='-1' href='javascript:void(0)' ng-if='!item.divider && item.click' ng-click='$eval(item.click);$hide()' ng-bind='item.text')


[15/52] ignite git commit: Web Console beta-3.

Posted by ak...@apache.org.
http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/src/main/js/app/modules/states/configuration/clusters/general/discovery/zookeeper/retrypolicy/custom.jade
----------------------------------------------------------------------
diff --git a/modules/web-console/src/main/js/app/modules/states/configuration/clusters/general/discovery/zookeeper/retrypolicy/custom.jade b/modules/web-console/src/main/js/app/modules/states/configuration/clusters/general/discovery/zookeeper/retrypolicy/custom.jade
deleted file mode 100644
index 6e631ab..0000000
--- a/modules/web-console/src/main/js/app/modules/states/configuration/clusters/general/discovery/zookeeper/retrypolicy/custom.jade
+++ /dev/null
@@ -1,24 +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.
-
-include ../../../../../../../../../app/helpers/jade/mixins.jade
-
--var model = 'backupItem.discovery.ZooKeeper.retryPolicy'
--var retry = model + '.Custom'
--var required = 'backupItem.discovery.kind === "ZooKeeper" && backupItem.discovery.ZooKeeper.retryPolicy.kind === "Custom"'
-
-.details-row
-    +java-class('Class name:', retry + '.className', 'customClassName', 'true', required, 'Custom retry policy implementation class name')

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/src/main/js/app/modules/states/configuration/clusters/general/discovery/zookeeper/retrypolicy/exponential-backoff.directive.js
----------------------------------------------------------------------
diff --git a/modules/web-console/src/main/js/app/modules/states/configuration/clusters/general/discovery/zookeeper/retrypolicy/exponential-backoff.directive.js b/modules/web-console/src/main/js/app/modules/states/configuration/clusters/general/discovery/zookeeper/retrypolicy/exponential-backoff.directive.js
deleted file mode 100644
index e68dff6..0000000
--- a/modules/web-console/src/main/js/app/modules/states/configuration/clusters/general/discovery/zookeeper/retrypolicy/exponential-backoff.directive.js
+++ /dev/null
@@ -1,27 +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 templateUrl from './exponential-backoff.jade';
-
-export default ['igniteConfigurationClustersGeneralDiscoveryZookeeperExponential', [() => {
-    return {
-        scope: true,
-        restrict: 'E',
-        templateUrl,
-        replace: true
-    };
-}]];

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/src/main/js/app/modules/states/configuration/clusters/general/discovery/zookeeper/retrypolicy/exponential-backoff.jade
----------------------------------------------------------------------
diff --git a/modules/web-console/src/main/js/app/modules/states/configuration/clusters/general/discovery/zookeeper/retrypolicy/exponential-backoff.jade b/modules/web-console/src/main/js/app/modules/states/configuration/clusters/general/discovery/zookeeper/retrypolicy/exponential-backoff.jade
deleted file mode 100644
index 9be2a71..0000000
--- a/modules/web-console/src/main/js/app/modules/states/configuration/clusters/general/discovery/zookeeper/retrypolicy/exponential-backoff.jade
+++ /dev/null
@@ -1,27 +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.
-
-include ../../../../../../../../../app/helpers/jade/mixins.jade
-
--var model = 'backupItem.discovery.ZooKeeper.retryPolicy.ExponentialBackoff'
-
-div
-    .details-row
-        +number('Base interval:', model + '.baseSleepTimeMs', 'expBaseSleepTimeMs', 'true', '1000', '0', 'Initial amount of time in ms to wait between retries')
-    .details-row
-        +number-min-max('Max retries:', model + '.maxRetries', 'expMaxRetries', 'true', '10', '0', '29', 'Max number of times to retry')
-    .details-row
-        +number('Max interval:', model + '.maxSleepMs', 'expMaxSleepMs', 'true', 'Integer.MAX_VALUE', '0', 'Max time in ms to sleep on each retry')

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/src/main/js/app/modules/states/configuration/clusters/general/discovery/zookeeper/retrypolicy/forever.directive.js
----------------------------------------------------------------------
diff --git a/modules/web-console/src/main/js/app/modules/states/configuration/clusters/general/discovery/zookeeper/retrypolicy/forever.directive.js b/modules/web-console/src/main/js/app/modules/states/configuration/clusters/general/discovery/zookeeper/retrypolicy/forever.directive.js
deleted file mode 100644
index 38bc2d8..0000000
--- a/modules/web-console/src/main/js/app/modules/states/configuration/clusters/general/discovery/zookeeper/retrypolicy/forever.directive.js
+++ /dev/null
@@ -1,27 +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 templateUrl from './forever.jade';
-
-export default ['igniteConfigurationClustersGeneralDiscoveryZookeeperForever', [() => {
-    return {
-        scope: true,
-        restrict: 'E',
-        templateUrl,
-        replace: true
-    };
-}]];

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/src/main/js/app/modules/states/configuration/clusters/general/discovery/zookeeper/retrypolicy/forever.jade
----------------------------------------------------------------------
diff --git a/modules/web-console/src/main/js/app/modules/states/configuration/clusters/general/discovery/zookeeper/retrypolicy/forever.jade b/modules/web-console/src/main/js/app/modules/states/configuration/clusters/general/discovery/zookeeper/retrypolicy/forever.jade
deleted file mode 100644
index f4045eb..0000000
--- a/modules/web-console/src/main/js/app/modules/states/configuration/clusters/general/discovery/zookeeper/retrypolicy/forever.jade
+++ /dev/null
@@ -1,22 +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.
-
-include ../../../../../../../../../app/helpers/jade/mixins.jade
-
--var model = 'backupItem.discovery.ZooKeeper.retryPolicy.Forever'
-
-.details-row
-    +number('Interval:', model + '.retryIntervalMs', 'feRetryIntervalMs', 'true', '1000', '0', 'Time in ms between retry attempts')

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/src/main/js/app/modules/states/configuration/clusters/general/discovery/zookeeper/retrypolicy/n-times.directive.js
----------------------------------------------------------------------
diff --git a/modules/web-console/src/main/js/app/modules/states/configuration/clusters/general/discovery/zookeeper/retrypolicy/n-times.directive.js b/modules/web-console/src/main/js/app/modules/states/configuration/clusters/general/discovery/zookeeper/retrypolicy/n-times.directive.js
deleted file mode 100644
index f369af8..0000000
--- a/modules/web-console/src/main/js/app/modules/states/configuration/clusters/general/discovery/zookeeper/retrypolicy/n-times.directive.js
+++ /dev/null
@@ -1,27 +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 templateUrl from './n-times.jade';
-
-export default ['igniteConfigurationClustersGeneralDiscoveryZookeeperNTimes', [() => {
-    return {
-        scope: true,
-        restrict: 'E',
-        templateUrl,
-        replace: true
-    };
-}]];

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/src/main/js/app/modules/states/configuration/clusters/general/discovery/zookeeper/retrypolicy/n-times.jade
----------------------------------------------------------------------
diff --git a/modules/web-console/src/main/js/app/modules/states/configuration/clusters/general/discovery/zookeeper/retrypolicy/n-times.jade b/modules/web-console/src/main/js/app/modules/states/configuration/clusters/general/discovery/zookeeper/retrypolicy/n-times.jade
deleted file mode 100644
index a4083b7..0000000
--- a/modules/web-console/src/main/js/app/modules/states/configuration/clusters/general/discovery/zookeeper/retrypolicy/n-times.jade
+++ /dev/null
@@ -1,25 +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.
-
-include ../../../../../../../../../app/helpers/jade/mixins.jade
-
--var model = 'backupItem.discovery.ZooKeeper.retryPolicy.NTimes'
-
-div
-    .details-row
-        +number('Retries:', model + '.n', 'n', 'true', '10', '0', 'Number of times to retry')
-    .details-row
-        +number('Interval:', model + '.sleepMsBetweenRetries', 'ntSleepMsBetweenRetries', 'true', '1000', '0', 'Time in ms between retry attempts')

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/src/main/js/app/modules/states/configuration/clusters/general/discovery/zookeeper/retrypolicy/one-time.directive.js
----------------------------------------------------------------------
diff --git a/modules/web-console/src/main/js/app/modules/states/configuration/clusters/general/discovery/zookeeper/retrypolicy/one-time.directive.js b/modules/web-console/src/main/js/app/modules/states/configuration/clusters/general/discovery/zookeeper/retrypolicy/one-time.directive.js
deleted file mode 100644
index e9e114d..0000000
--- a/modules/web-console/src/main/js/app/modules/states/configuration/clusters/general/discovery/zookeeper/retrypolicy/one-time.directive.js
+++ /dev/null
@@ -1,27 +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 templateUrl from './one-time.jade';
-
-export default ['igniteConfigurationClustersGeneralDiscoveryZookeeperOneTime', [() => {
-    return {
-        scope: true,
-        restrict: 'E',
-        templateUrl,
-        replace: true
-    };
-}]];

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/src/main/js/app/modules/states/configuration/clusters/general/discovery/zookeeper/retrypolicy/one-time.jade
----------------------------------------------------------------------
diff --git a/modules/web-console/src/main/js/app/modules/states/configuration/clusters/general/discovery/zookeeper/retrypolicy/one-time.jade b/modules/web-console/src/main/js/app/modules/states/configuration/clusters/general/discovery/zookeeper/retrypolicy/one-time.jade
deleted file mode 100644
index f259630..0000000
--- a/modules/web-console/src/main/js/app/modules/states/configuration/clusters/general/discovery/zookeeper/retrypolicy/one-time.jade
+++ /dev/null
@@ -1,23 +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.
-
-include ../../../../../../../../../app/helpers/jade/mixins.jade
-
--var model = 'backupItem.discovery.ZooKeeper.retryPolicy.OneTime'
-
-div
-    .details-row
-        +number('Interval:', model + '.sleepMsBetweenRetry', 'oneSleepMsBetweenRetry', 'true', '1000', '0', 'Time in ms to retry attempt')

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/src/main/js/app/modules/states/configuration/clusters/general/discovery/zookeeper/retrypolicy/until-elapsed.directive.js
----------------------------------------------------------------------
diff --git a/modules/web-console/src/main/js/app/modules/states/configuration/clusters/general/discovery/zookeeper/retrypolicy/until-elapsed.directive.js b/modules/web-console/src/main/js/app/modules/states/configuration/clusters/general/discovery/zookeeper/retrypolicy/until-elapsed.directive.js
deleted file mode 100644
index 4ab76b2..0000000
--- a/modules/web-console/src/main/js/app/modules/states/configuration/clusters/general/discovery/zookeeper/retrypolicy/until-elapsed.directive.js
+++ /dev/null
@@ -1,27 +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 templateUrl from './until-elapsed.jade';
-
-export default ['igniteConfigurationClustersGeneralDiscoveryZookeeperUntilElapsed', [() => {
-    return {
-        scope: true,
-        restrict: 'E',
-        templateUrl,
-        replace: true
-    };
-}]];

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/src/main/js/app/modules/states/configuration/clusters/general/discovery/zookeeper/retrypolicy/until-elapsed.jade
----------------------------------------------------------------------
diff --git a/modules/web-console/src/main/js/app/modules/states/configuration/clusters/general/discovery/zookeeper/retrypolicy/until-elapsed.jade b/modules/web-console/src/main/js/app/modules/states/configuration/clusters/general/discovery/zookeeper/retrypolicy/until-elapsed.jade
deleted file mode 100644
index 24a884e..0000000
--- a/modules/web-console/src/main/js/app/modules/states/configuration/clusters/general/discovery/zookeeper/retrypolicy/until-elapsed.jade
+++ /dev/null
@@ -1,25 +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.
-
-include ../../../../../../../../../app/helpers/jade/mixins.jade
-
--var model = 'backupItem.discovery.ZooKeeper.retryPolicy.UntilElapsed'
-
-div
-    .details-row
-        +number('Total time:', model + '.maxElapsedTimeMs', 'ueMaxElapsedTimeMs', 'true', '60000', '0', 'Total time in ms for execution of retry attempt')
-    .details-row
-        +number('Interval:', model + '.sleepMsBetweenRetries', 'ueSleepMsBetweenRetries', 'true', '1000', '0', 'Time in ms between retry attempts')

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/src/main/js/app/modules/states/configuration/clusters/igfs.directive.js
----------------------------------------------------------------------
diff --git a/modules/web-console/src/main/js/app/modules/states/configuration/clusters/igfs.directive.js b/modules/web-console/src/main/js/app/modules/states/configuration/clusters/igfs.directive.js
deleted file mode 100644
index 74d4826..0000000
--- a/modules/web-console/src/main/js/app/modules/states/configuration/clusters/igfs.directive.js
+++ /dev/null
@@ -1,27 +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 templateUrl from './igfs.jade';
-
-export default ['igniteConfigurationClustersIgfs', [() => {
-    return {
-        scope: true,
-        restrict: 'E',
-        templateUrl,
-        replace: true
-    };
-}]];

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/src/main/js/app/modules/states/configuration/clusters/igfs.jade
----------------------------------------------------------------------
diff --git a/modules/web-console/src/main/js/app/modules/states/configuration/clusters/igfs.jade b/modules/web-console/src/main/js/app/modules/states/configuration/clusters/igfs.jade
deleted file mode 100644
index de20dfe..0000000
--- a/modules/web-console/src/main/js/app/modules/states/configuration/clusters/igfs.jade
+++ /dev/null
@@ -1,37 +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.
-
-include ../../../../../app/helpers/jade/mixins.jade
-
--var form = 'igfs'
--var model = 'backupItem'
-
-form.panel.panel-default(name=form novalidate)
-    .panel-heading(bs-collapse-toggle ng-click='ui.loadPanel("#{form}")')
-        ignite-form-panel-chevron
-        label IGFS
-        ignite-form-field-tooltip.tipLabel
-            | IGFS (Ignite In-Memory File System) configurations
-        ignite-form-revert
-    .panel-collapse(role='tabpanel' bs-collapse-target id=form)
-        .panel-body(ng-if='ui.isPanelLoaded("#{form}")')
-            .col-sm-6
-                .settings-row
-                    +dropdown-multiple('<span>IGFS:</span><a ui-sref="base.configuration.igfs({linkId: linkId()})"> (add)</a>',
-                        model + '.igfss', 'igfss', 'true', 'Choose IGFS', 'No IGFS configured', 'igfss',
-                        'Select IGFS to start in cluster or add a new IGFS')
-            .col-sm-6
-                +preview-xml-java(model, 'igfss', 'igfss')

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/src/main/js/app/modules/states/configuration/clusters/logger.directive.js
----------------------------------------------------------------------
diff --git a/modules/web-console/src/main/js/app/modules/states/configuration/clusters/logger.directive.js b/modules/web-console/src/main/js/app/modules/states/configuration/clusters/logger.directive.js
deleted file mode 100644
index 8aec165..0000000
--- a/modules/web-console/src/main/js/app/modules/states/configuration/clusters/logger.directive.js
+++ /dev/null
@@ -1,27 +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 templateUrl from './logger.jade';
-
-export default ['igniteConfigurationClustersLogger', [() => {
-    return {
-        scope: true,
-        restrict: 'E',
-        templateUrl,
-        replace: true
-    };
-}]];

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/src/main/js/app/modules/states/configuration/clusters/logger.jade
----------------------------------------------------------------------
diff --git a/modules/web-console/src/main/js/app/modules/states/configuration/clusters/logger.jade b/modules/web-console/src/main/js/app/modules/states/configuration/clusters/logger.jade
deleted file mode 100644
index 3406ff5..0000000
--- a/modules/web-console/src/main/js/app/modules/states/configuration/clusters/logger.jade
+++ /dev/null
@@ -1,65 +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.
-
-include ../../../../../app/helpers/jade/mixins.jade
-
--var model = 'backupItem.logger'
--var form = 'logger'
--var kind = model + '.kind'
-
-form.panel.panel-default(name=form novalidate)
-    .panel-heading(bs-collapse-toggle ng-click='ui.loadPanel("#{form}")')
-        ignite-form-panel-chevron
-        label Logger configuration
-        ignite-form-field-tooltip.tipLabel
-            | Logging functionality used throughout the system
-        ignite-form-revert
-    .panel-collapse(role='tabpanel' bs-collapse-target id=form)
-        .panel-body(ng-if='ui.isPanelLoaded("#{form}")')
-            .col-sm-6
-                .settings-row
-                    +dropdown('Logger:', kind, 'logger', 'true', 'Default',
-                        '[\
-                            {value: "Log4j", label: "Apache Log4j"},\
-                            {value: "Log4j2", label: "Apache Log4j 2"},\
-                            {value: "SLF4J", label: "Simple Logging Facade (SLF4J)"},\
-                            {value: "Java", label: "Java logger (JUL)"},\
-                            {value: "JCL", label: "Jakarta Commons Logging (JCL)"},\
-                            {value: "Null", label: "Null logger"},\
-                            {value: "Custom", label: "Custom"},\
-                            {value: undefined, label: "Default"}\
-                        ]',
-                        'Logger implementations\
-                        <ul>\
-                            <li>Apache Log4j - log4j-based logger</li>\
-                            <li>Apache Log4j 2 - Log4j2-based logger</li>\
-                            <li>Simple Logging Facade (SLF4J) - SLF4j-based logger</li>\
-                            <li>Java logger (JUL) - built in java logger</li>\
-                            <li>Jakarta Commons Logging (JCL) - wraps any JCL (Jakarta Commons Logging) loggers</li>\
-                            <li>Null logger - logger which does not output anything</li>\
-                            <li>Custom - custom logger implementation</li>\
-                            <li>Default - Apache Log4j if awailable on classpath or Java logger otherwise</li>\
-                        </ul>')
-                .settings-row(ng-show='#{kind} && (#{kind} === "Log4j2" || #{kind} === "Log4j" || #{kind} === "Custom")')
-                    .panel-details
-                        ignite-configuration-clusters-logger-log4j2(
-                            ng-show='#{kind} === "Log4j2"')
-                        ignite-configuration-clusters-logger-log4j(
-                            ng-show='#{kind} === "Log4j"')
-                        ignite-configuration-clusters-logger-custom(
-                            ng-show='#{kind} === "Custom"')
-            .col-sm-6
-                +preview-xml-java(model, 'clusterLogger')

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/src/main/js/app/modules/states/configuration/clusters/logger/custom.directive.js
----------------------------------------------------------------------
diff --git a/modules/web-console/src/main/js/app/modules/states/configuration/clusters/logger/custom.directive.js b/modules/web-console/src/main/js/app/modules/states/configuration/clusters/logger/custom.directive.js
deleted file mode 100644
index 999a3ca..0000000
--- a/modules/web-console/src/main/js/app/modules/states/configuration/clusters/logger/custom.directive.js
+++ /dev/null
@@ -1,27 +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 templateUrl from './custom.jade';
-
-export default ['igniteConfigurationClustersLoggerCustom', [() => {
-    return {
-        scope: true,
-        restrict: 'E',
-        templateUrl,
-        replace: true
-    };
-}]];

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/src/main/js/app/modules/states/configuration/clusters/logger/custom.jade
----------------------------------------------------------------------
diff --git a/modules/web-console/src/main/js/app/modules/states/configuration/clusters/logger/custom.jade b/modules/web-console/src/main/js/app/modules/states/configuration/clusters/logger/custom.jade
deleted file mode 100644
index 58dba15..0000000
--- a/modules/web-console/src/main/js/app/modules/states/configuration/clusters/logger/custom.jade
+++ /dev/null
@@ -1,24 +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.
-
-include ../../../../../../app/helpers/jade/mixins.jade
-
--var model = 'backupItem.logger.Custom'
--var required = 'backupItem.logger.kind === "Custom"'
-
-div
-    .details-row
-        +java-class('Class:', model + '.class', 'customLogger', 'true', required, 'Logger implementation class')

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/src/main/js/app/modules/states/configuration/clusters/logger/log4j.directive.js
----------------------------------------------------------------------
diff --git a/modules/web-console/src/main/js/app/modules/states/configuration/clusters/logger/log4j.directive.js b/modules/web-console/src/main/js/app/modules/states/configuration/clusters/logger/log4j.directive.js
deleted file mode 100644
index 32f55e9..0000000
--- a/modules/web-console/src/main/js/app/modules/states/configuration/clusters/logger/log4j.directive.js
+++ /dev/null
@@ -1,27 +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 templateUrl from './log4j.jade';
-
-export default ['igniteConfigurationClustersLoggerLog4j', [() => {
-    return {
-        scope: true,
-        restrict: 'E',
-        templateUrl,
-        replace: true
-    };
-}]];

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/src/main/js/app/modules/states/configuration/clusters/logger/log4j.jade
----------------------------------------------------------------------
diff --git a/modules/web-console/src/main/js/app/modules/states/configuration/clusters/logger/log4j.jade b/modules/web-console/src/main/js/app/modules/states/configuration/clusters/logger/log4j.jade
deleted file mode 100644
index 97f407d..0000000
--- a/modules/web-console/src/main/js/app/modules/states/configuration/clusters/logger/log4j.jade
+++ /dev/null
@@ -1,49 +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.
-
-include ../../../../../../app/helpers/jade/mixins.jade
-
--var model = 'backupItem.logger.Log4j'
--var pathRequired = model + '.mode === "Path" && backupItem.logger.kind === "Log4j"'
-
-div
-    .details-row
-        +dropdown('Level:', model + '.level', 'log4jLevel', 'true', 'Default',
-            '[\
-                {value: "OFF", label: "OFF"},\
-                {value: "FATAL", label: "FATAL"},\
-                {value: "ERROR", label: "ERROR"},\
-                {value: "WARN", label: "WARN"},\
-                {value: "INFO", label: "INFO"},\
-                {value: "DEBUG", label: "DEBUG"},\
-                {value: "TRACE", label: "TRACE"},\
-                {value: "ALL", label: "ALL"},\
-                {value: undefined, label: "Default"}\
-            ]',
-            'Level for internal log4j implementation')
-    .details-row
-        +dropdown-required('Logger configuration:', model + '.mode', 'log4jMode', 'true', 'true', 'Choose logger mode',
-            '[\
-                {value: "Default", label: "Default"},\
-                {value: "Path", label: "Path"}\
-            ]',
-            'Choose logger configuration\
-            <ul>\
-                <li>Default - default logger</li>\
-                <li>Path - path or URI to XML configuration</li>\
-            </ul>')
-    .details-row(ng-show=pathRequired)
-        +text('Path:', model + '.path', 'log4jPath', pathRequired, 'Input path', 'Path or URI to XML configuration')

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/src/main/js/app/modules/states/configuration/clusters/logger/log4j2.directive.js
----------------------------------------------------------------------
diff --git a/modules/web-console/src/main/js/app/modules/states/configuration/clusters/logger/log4j2.directive.js b/modules/web-console/src/main/js/app/modules/states/configuration/clusters/logger/log4j2.directive.js
deleted file mode 100644
index 81ae296..0000000
--- a/modules/web-console/src/main/js/app/modules/states/configuration/clusters/logger/log4j2.directive.js
+++ /dev/null
@@ -1,27 +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 templateUrl from './log4j2.jade';
-
-export default ['igniteConfigurationClustersLoggerLog4j2', [() => {
-    return {
-        scope: true,
-        restrict: 'E',
-        templateUrl,
-        replace: true
-    };
-}]];

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/src/main/js/app/modules/states/configuration/clusters/logger/log4j2.jade
----------------------------------------------------------------------
diff --git a/modules/web-console/src/main/js/app/modules/states/configuration/clusters/logger/log4j2.jade b/modules/web-console/src/main/js/app/modules/states/configuration/clusters/logger/log4j2.jade
deleted file mode 100644
index b4cea90..0000000
--- a/modules/web-console/src/main/js/app/modules/states/configuration/clusters/logger/log4j2.jade
+++ /dev/null
@@ -1,38 +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.
-
-include ../../../../../../app/helpers/jade/mixins.jade
-
--var model = 'backupItem.logger.Log4j2'
--var log4j2Required = 'backupItem.logger.kind === "Log4j2"'
-
-div
-    .details-row
-        +dropdown('Level:', model + '.level', 'log4j2Level', 'true', 'Default',
-            '[\
-                {value: "OFF", label: "OFF"},\
-                {value: "FATAL", label: "FATAL"},\
-                {value: "ERROR", label: "ERROR"},\
-                {value: "WARN", label: "WARN"},\
-                {value: "INFO", label: "INFO"},\
-                {value: "DEBUG", label: "DEBUG"},\
-                {value: "TRACE", label: "TRACE"},\
-                {value: "ALL", label: "ALL"},\
-                {value: undefined, label: "Default"}\
-            ]',
-            'Level for internal log4j2 implementation')
-    .details-row
-        +text('Path:', model + '.path', 'log4j2Path', log4j2Required, 'Input path', 'Path or URI to XML configuration')

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/src/main/js/app/modules/states/configuration/clusters/marshaller.directive.js
----------------------------------------------------------------------
diff --git a/modules/web-console/src/main/js/app/modules/states/configuration/clusters/marshaller.directive.js b/modules/web-console/src/main/js/app/modules/states/configuration/clusters/marshaller.directive.js
deleted file mode 100644
index b4175b0..0000000
--- a/modules/web-console/src/main/js/app/modules/states/configuration/clusters/marshaller.directive.js
+++ /dev/null
@@ -1,27 +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 templateUrl from './marshaller.jade';
-
-export default ['igniteConfigurationClustersMarshaller', [() => {
-    return {
-        scope: true,
-        restrict: 'E',
-        templateUrl,
-        replace: true
-    };
-}]];

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/src/main/js/app/modules/states/configuration/clusters/marshaller.jade
----------------------------------------------------------------------
diff --git a/modules/web-console/src/main/js/app/modules/states/configuration/clusters/marshaller.jade b/modules/web-console/src/main/js/app/modules/states/configuration/clusters/marshaller.jade
deleted file mode 100644
index fbeb11a..0000000
--- a/modules/web-console/src/main/js/app/modules/states/configuration/clusters/marshaller.jade
+++ /dev/null
@@ -1,69 +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.
-
-include ../../../../../app/helpers/jade/mixins.jade
-
--var form = 'marshaller'
--var model = 'backupItem'
--var marshaller = model + '.marshaller'
--var optMarshaller = marshaller + '.OptimizedMarshaller'
-
-form.panel.panel-default(name=form novalidate)
-    .panel-heading(bs-collapse-toggle ng-click='ui.loadPanel("#{form}")')
-        ignite-form-panel-chevron
-        label Marshaller
-        ignite-form-field-tooltip.tipLabel
-            | Marshaller allows to marshal or unmarshal objects in grid#[br]
-            | It provides serialization/deserialization mechanism for all instances that are sent across networks or are otherwise serialized
-        ignite-form-revert
-    .panel-collapse(role='tabpanel' bs-collapse-target id=form)
-        .panel-body(ng-if='ui.isPanelLoaded("#{form}")')
-            .col-sm-6
-                .settings-row
-                    +dropdown('Marshaller:', marshaller + '.kind', 'kind', 'true', 'Choose marshaller',
-                        '[\
-                            {value: "OptimizedMarshaller", label: "OptimizedMarshaller"},\
-                            {value: "JdkMarshaller", label: "JdkMarshaller"},\
-                            {value: undefined, label: "Not set"}\
-                        ]',
-                        'Instance of marshaller to use in grid<br/>\
-                        If not provided, BinaryMarshaller will be used')
-                    a.customize(
-                        ng-if='#{marshaller}.kind && #{marshaller}.kind === "OptimizedMarshaller"'
-                        ng-click='#{marshaller}.expanded = !#{marshaller}.expanded'
-                    ) {{ #{marshaller}.expanded ? "Hide settings" : "Show settings"}}
-                .settings-row
-                    .panel-details(ng-if='#{marshaller}.expanded && #{marshaller}.kind === "OptimizedMarshaller"')
-                        .details-row
-                            +number('Streams pool size:', optMarshaller + '.poolSize', 'poolSize', 'true', '0', '0',
-                                'Specifies size of cached object streams used by marshaller<br/>\
-                                Object streams are cached for performance reason to avoid costly recreation for every serialization routine<br/>\
-                                If 0 (default), pool is not used and each thread has its own cached object stream which it keeps reusing<br/>\
-                                Since each stream has an internal buffer, creating a stream for each thread can lead to high memory consumption if many large messages are marshalled or unmarshalled concurrently<br/>\
-                                Consider using pool in this case. This will limit number of streams that can be created and, therefore, decrease memory consumption<br/>\
-                                NOTE: Using streams pool can decrease performance since streams will be shared between different threads which will lead to more frequent context switching')
-                        .details-row
-                            +checkbox('Require serializable', optMarshaller + '.requireSerializable', 'requireSerializable',
-                                'Whether marshaller should require Serializable interface or not')
-                .settings-row
-                    +checkbox('Marshal local jobs', model + '.marshalLocalJobs', 'marshalLocalJobs', 'If this flag is enabled, jobs mapped to local node will be marshalled as if it was remote node')
-                .settings-row
-                    +number('Keep alive time:', model + '.marshallerCacheKeepAliveTime', 'marshallerCacheKeepAliveTime', 'true', '10000', '0')
-                .settings-row
-                    +number('Pool size:', model + '.marshallerCacheThreadPoolSize', 'marshallerCacheThreadPoolSize', 'true', 'max(8, availableProcessors) * 2', '0',
-                        'Default size of thread pool that is in charge of processing marshaller messages')
-            .col-sm-6
-                +preview-xml-java(model, 'clusterMarshaller')

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/src/main/js/app/modules/states/configuration/clusters/metrics.directive.js
----------------------------------------------------------------------
diff --git a/modules/web-console/src/main/js/app/modules/states/configuration/clusters/metrics.directive.js b/modules/web-console/src/main/js/app/modules/states/configuration/clusters/metrics.directive.js
deleted file mode 100644
index 9b8ddc3..0000000
--- a/modules/web-console/src/main/js/app/modules/states/configuration/clusters/metrics.directive.js
+++ /dev/null
@@ -1,27 +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 templateUrl from './metrics.jade';
-
-export default ['igniteConfigurationClustersMetrics', [() => {
-    return {
-        scope: true,
-        restrict: 'E',
-        templateUrl,
-        replace: true
-    };
-}]];

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/src/main/js/app/modules/states/configuration/clusters/metrics.jade
----------------------------------------------------------------------
diff --git a/modules/web-console/src/main/js/app/modules/states/configuration/clusters/metrics.jade b/modules/web-console/src/main/js/app/modules/states/configuration/clusters/metrics.jade
deleted file mode 100644
index 4d41d10..0000000
--- a/modules/web-console/src/main/js/app/modules/states/configuration/clusters/metrics.jade
+++ /dev/null
@@ -1,50 +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.
-
-include ../../../../../app/helpers/jade/mixins.jade
-
--var form = 'metrics'
--var model = 'backupItem'
-
-form.panel.panel-default(name=form novalidate)
-    .panel-heading(bs-collapse-toggle ng-click='ui.loadPanel("#{form}")')
-        ignite-form-panel-chevron
-        label Metrics
-        ignite-form-field-tooltip.tipLabel
-            | Cluster runtime metrics settings
-        ignite-form-revert
-    .panel-collapse(role='tabpanel' bs-collapse-target id=form)
-        .panel-body(ng-if='ui.isPanelLoaded("#{form}")')
-            .col-sm-6
-                .settings-row
-                    +number('Elapsed time:', model + '.metricsExpireTime', 'metricsExpireTime', 'true', 'Long.MAX_VALUE', '1',
-                        'Time in milliseconds after which a certain metric value is considered expired')
-                .settings-row
-                    +number('History size:', model + '.metricsHistorySize', 'metricsHistorySize', 'true', '10000', '1',
-                        'Number of metrics kept in history to compute totals and averages')
-                .settings-row
-                    +number('Log frequency:', model + '.metricsLogFrequency', 'metricsLogFrequency', 'true', '60000', '0',
-                        'Frequency of metrics log print out. To disable set to 0')
-                .settings-row
-                    +number('Update frequency:', model + '.metricsUpdateFrequency', 'metricsUpdateFrequency', 'true', '2000', '0',
-                        'Job metrics update frequency in milliseconds\
-                        <ul>\
-                            <li>If set to -1 job metrics are never updated</li>\
-                            <li>If set to 0 job metrics are updated on each job start and finish</li>\
-                            <li>Positive value defines the actual update frequency</li>\
-                        </ul>')
-            .col-sm-6
-                +preview-xml-java(model, 'clusterMetrics')

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/src/main/js/app/modules/states/configuration/clusters/ssl.directive.js
----------------------------------------------------------------------
diff --git a/modules/web-console/src/main/js/app/modules/states/configuration/clusters/ssl.directive.js b/modules/web-console/src/main/js/app/modules/states/configuration/clusters/ssl.directive.js
deleted file mode 100644
index ded5bf0..0000000
--- a/modules/web-console/src/main/js/app/modules/states/configuration/clusters/ssl.directive.js
+++ /dev/null
@@ -1,27 +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 templateUrl from './ssl.jade';
-
-export default ['igniteConfigurationClustersSsl', [() => {
-    return {
-        scope: true,
-        restrict: 'E',
-        templateUrl,
-        replace: true
-    };
-}]];

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/src/main/js/app/modules/states/configuration/clusters/ssl.jade
----------------------------------------------------------------------
diff --git a/modules/web-console/src/main/js/app/modules/states/configuration/clusters/ssl.jade b/modules/web-console/src/main/js/app/modules/states/configuration/clusters/ssl.jade
deleted file mode 100644
index 0a25e79..0000000
--- a/modules/web-console/src/main/js/app/modules/states/configuration/clusters/ssl.jade
+++ /dev/null
@@ -1,108 +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.
-
-include ../../../../../app/helpers/jade/mixins.jade
-
--var form = 'sslConfiguration'
--var cluster = 'backupItem'
--var enabled = 'backupItem.sslEnabled'
--var model = cluster + '.sslContextFactory'
--var trust = model + '.trustManagers'
-
-form.panel.panel-default(name=form novalidate)
-    .panel-heading(bs-collapse-toggle ng-click='ui.loadPanel("#{form}")')
-        ignite-form-panel-chevron
-        label(id='sslConfiguration-title') SSL configuration
-        ignite-form-field-tooltip.tipLabel
-            | Settings for SSL configuration
-        ignite-form-revert
-    .panel-collapse(role='tabpanel' bs-collapse-target id=form)
-        .panel-body(ng-if='ui.isPanelLoaded("#{form}")')
-            .col-sm-6
-                .settings-row
-                    +checkbox('Enabled', enabled, 'sslEnabled', 'Flag indicating whether to configure SSL configuration')
-                .settings-row
-                    +text-options('Algorithm to create a key manager:', model + '.keyAlgorithm', 'keyAlgorithm', '["SumX509", "X509"]', enabled, 'false', 'SumX509',
-                        'Sets key manager algorithm that will be used to create a key manager<br/>\
-                        Notice that in most cased default value suites well, however, on Android platform this value need to be set to X509')
-                .settings-row
-                    +text-enabled('Key store file:', model + '.keyStoreFilePath', 'keyStoreFilePath', enabled, enabled, 'Path to the key store file',
-                        'Path to the key store file<br/>\
-                        This is a mandatory parameter since ssl context could not be initialized without key manager')
-                .settings-row
-                    +text-options('Key store type:', model + '.keyStoreType', 'keyStoreType', '["JKS", "PCKS11", "PCKS12"]', enabled, 'false', 'JKS',
-                        'Key store type used in context initialization')
-                .settings-row
-                    +text-options('Protocol:', model + '.protocol', 'protocol', '["TSL", "SSL"]', enabled, 'false', 'TSL', 'Protocol for secure transport')
-                .settings-row
-                    -var trustManagersForm = 'trustManagers'
-
-                    ignite-form-group(ng-form='trustManagers' ng-model='#{trust}')
-                        -var uniqueTip = 'Such trust manager already exists!'
-
-                        ignite-form-field-label
-                            | Trust managers
-                        ignite-form-group-tooltip
-                            | Pre-configured trust managers
-                        ignite-form-group-add(ng-show='#{enabled}' ng-click='(group.add = [{}])')
-                            | Add new trust manager.
-
-                        .group-content(ng-if='#{trust}.length')
-                            -var field = 'edit'
-                            -var valid = 'form[ngModelName].$valid'
-                            -var unique = 'form[ngModelName].$error.igniteUnique'
-                            -var save = trust + '[$index] = ' + field
-                            -var reset = 'field.edit = false'
-
-                            div(ng-show=enabled)
-                                ignite-form-field(ng-repeat='model in #{trust} track by $index' type='internal' name='Trust manager')
-                                    .indexField
-                                        | {{ $index+1 }})
-                                    +table-remove-conditional-button(trust, enabled, 'Remove trust manager')
-                                    span(ng-hide='field.edit')
-                                        a.labelFormField(ng-click='#{enabled} && (field.edit = true)') {{ model }}
-                                    span(ng-if='field.edit' ng-init='#{field} = model')
-                                        +table-java-class-field('Trust manager', field, trust, valid, save, false)
-                                            +table-save-button(valid, save, false)
-                                            +unique-feedback(unique, uniqueTip)
-                            div(ng-hide=enabled)
-                                ignite-form-field(ng-repeat='model in #{trust} track by $index' type='internal' name='Trust manager')
-                                    .labelFormField.labelField
-                                        | {{ $index+1 }})
-                                    span.labelFormField
-                                        | {{ model }}
-
-                        .group-content(ng-repeat='field in group.add')
-                            -var field = 'new'
-                            -var valid = 'form[ngModelName].$valid'
-                            -var unique = 'form[ngModelName].$error.igniteUnique'
-                            -var save = trust + '.push(' + field + ')'
-
-                            ignite-form-field(type='internal' name='Trust manager')
-                                +table-java-class-field('Trust manager', field, trust, valid, save, true)
-                                    +table-save-button(valid, save, true)
-                                    +unique-feedback(unique, uniqueTip)
-
-                        .group-content-empty(ng-if='!(#{trust}.length) && !group.add.length')
-                            | Not defined
-
-                .settings-row(ng-if='!#{trust}.length')
-                    +text-enabled('Trust store file:', model + '.trustStoreFilePath', 'trustStoreFilePath', enabled, 'false', 'Path to the trust store file', 'Path to the trust store file')
-                .settings-row(ng-if='!#{trust}.length')
-                    +text-options('Trust store type:', model + '.trustStoreType', 'trustStoreType', '["JKS", "PCKS11", "PCKS12"]', enabled, 'false', 'JKS',
-                        'Trust store type used in context initialization')
-            .col-sm-6
-                +preview-xml-java(cluster, 'clusterSsl')

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/src/main/js/app/modules/states/configuration/clusters/swap.directive.js
----------------------------------------------------------------------
diff --git a/modules/web-console/src/main/js/app/modules/states/configuration/clusters/swap.directive.js b/modules/web-console/src/main/js/app/modules/states/configuration/clusters/swap.directive.js
deleted file mode 100644
index c340c4b..0000000
--- a/modules/web-console/src/main/js/app/modules/states/configuration/clusters/swap.directive.js
+++ /dev/null
@@ -1,27 +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 templateUrl from './swap.jade';
-
-export default ['igniteConfigurationClustersSwap', [() => {
-    return {
-        scope: true,
-        restrict: 'E',
-        templateUrl,
-        replace: true
-    };
-}]];

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/src/main/js/app/modules/states/configuration/clusters/swap.jade
----------------------------------------------------------------------
diff --git a/modules/web-console/src/main/js/app/modules/states/configuration/clusters/swap.jade b/modules/web-console/src/main/js/app/modules/states/configuration/clusters/swap.jade
deleted file mode 100644
index fd62fe8..0000000
--- a/modules/web-console/src/main/js/app/modules/states/configuration/clusters/swap.jade
+++ /dev/null
@@ -1,67 +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.
-
-include ../../../../../app/helpers/jade/mixins.jade
-
--var form = 'swap'
--var model = 'backupItem'
--var swapModel = model + '.swapSpaceSpi'
--var fileSwapModel = swapModel + '.FileSwapSpaceSpi'
-
-form.panel.panel-default(name=form novalidate)
-    .panel-heading(bs-collapse-toggle ng-click='ui.loadPanel("#{form}")')
-        ignite-form-panel-chevron
-        label Swap
-        ignite-form-field-tooltip.tipLabel
-            | Settings for overflow data to disk if it cannot fit in memory
-        ignite-form-revert
-    .panel-collapse(role='tabpanel' bs-collapse-target id=form)
-        .panel-body(ng-if='ui.isPanelLoaded("#{form}")')
-            .col-sm-6
-                .settings-row
-                    +dropdown('Swap space SPI:', swapModel + '.kind', 'swapSpaceSpi', 'true', 'Choose swap SPI',
-                        '[\
-                            {value: "FileSwapSpaceSpi", label: "File-based swap"},\
-                            {value: undefined, label: "Not set"}\
-                        ]',
-                        'Provides a mechanism in grid for storing data on disk<br/>\
-                        Ignite cache uses swap space to overflow data to disk if it cannot fit in memory')
-                    a.customize(
-                        ng-if='#{swapModel}.kind'
-                        ng-click='#{swapModel}.expanded = !#{swapModel}.expanded'
-                    ) {{ #{swapModel}.expanded ? "Hide settings" : "Show settings"}}
-                .settings-row
-                    .panel-details(ng-if='#{swapModel}.expanded && #{swapModel}.kind')
-                        .details-row
-                            +text('Base directory:', fileSwapModel + '.baseDirectory', 'baseDirectory', 'false', 'swapspace',
-                                'Base directory where to write files')
-                        .details-row
-                            +number('Read stripe size:', fileSwapModel + '.readStripesNumber', 'readStripesNumber', 'true', 'availableProcessors', '0',
-                                'Read stripe size defines number of file channels to be used concurrently')
-                        .details-row
-                            +number-min-max-step('Maximum sparsity:', fileSwapModel + '.maximumSparsity', 'maximumSparsity', 'true', '0.5', '0', '0.999', '0.05',
-                                'This property defines maximum acceptable wasted file space to whole file size ratio<br/>\
-                                When this ratio becomes higher than specified number compacting thread starts working')
-                        .details-row
-                            +number('Max write queue size:', fileSwapModel + '.maxWriteQueueSize', 'maxWriteQueueSize', 'true', '1024 * 1024', '0',
-                                'Max write queue size in bytes<br/>\
-                                If there are more values are waiting for being written to disk then specified size, SPI will block on store operation')
-                        .details-row
-                            +number('Write buffer size:', fileSwapModel + '.writeBufferSize', 'writeBufferSize', 'true', '64 * 1024', '0',
-                                'Write buffer size in bytes<br/>\
-                                Write to disk occurs only when this buffer is full')
-            .col-sm-6
-                +preview-xml-java(model, 'clusterSwap')

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/src/main/js/app/modules/states/configuration/clusters/thread.directive.js
----------------------------------------------------------------------
diff --git a/modules/web-console/src/main/js/app/modules/states/configuration/clusters/thread.directive.js b/modules/web-console/src/main/js/app/modules/states/configuration/clusters/thread.directive.js
deleted file mode 100644
index f504e67..0000000
--- a/modules/web-console/src/main/js/app/modules/states/configuration/clusters/thread.directive.js
+++ /dev/null
@@ -1,27 +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 templateUrl from './thread.jade';
-
-export default ['igniteConfigurationClustersThread', [() => {
-    return {
-        scope: true,
-        restrict: 'E',
-        templateUrl,
-        replace: true
-    };
-}]];

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/src/main/js/app/modules/states/configuration/clusters/thread.jade
----------------------------------------------------------------------
diff --git a/modules/web-console/src/main/js/app/modules/states/configuration/clusters/thread.jade b/modules/web-console/src/main/js/app/modules/states/configuration/clusters/thread.jade
deleted file mode 100644
index 20803aa..0000000
--- a/modules/web-console/src/main/js/app/modules/states/configuration/clusters/thread.jade
+++ /dev/null
@@ -1,48 +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.
-
-include ../../../../../app/helpers/jade/mixins.jade
-
--var form = 'pools'
--var model = 'backupItem'
-
-form.panel.panel-default(name=form novalidate)
-    .panel-heading(bs-collapse-toggle ng-click='ui.loadPanel("#{form}")')
-        ignite-form-panel-chevron
-        label Thread pools size
-        ignite-form-field-tooltip.tipLabel
-            | Settings for node thread pools
-        ignite-form-revert
-    .panel-collapse(role='tabpanel' bs-collapse-target id=form)
-        .panel-body(ng-if='ui.isPanelLoaded("#{form}")')
-            .col-sm-6
-                .settings-row
-                    +number('Public:', model + '.publicThreadPoolSize', 'publicThreadPoolSize', 'true', 'max(8, availableProcessors) * 2', '1',
-                        'Thread pool that is in charge of processing ComputeJob, GridJobs and user messages sent to node')
-                .settings-row
-                    +number('System:', model + '.systemThreadPoolSize', 'systemThreadPoolSize', 'true', 'max(8, availableProcessors) * 2', '1',
-                        'Thread pool that is in charge of processing internal system messages')
-                .settings-row
-                    +number('Management:', model + '.managementThreadPoolSize', 'managementThreadPoolSize', 'true', '4', '1',
-                        'Thread pool that is in charge of processing internal and Visor ComputeJob, GridJobs')
-                .settings-row
-                    +number('IGFS:', model + '.igfsThreadPoolSize', 'igfsThreadPoolSize', 'true', 'availableProcessors', '1',
-                        'Thread pool that is in charge of processing outgoing IGFS messages')
-                .settings-row
-                    +number('Rebalance:', model + '.rebalanceThreadPoolSize', 'rebalanceThreadPoolSize', 'true', '1', '1',
-                        'Max count of threads can be used at rebalancing')
-            .col-sm-6
-                +preview-xml-java(model, 'clusterPools')

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/src/main/js/app/modules/states/configuration/clusters/time.directive.js
----------------------------------------------------------------------
diff --git a/modules/web-console/src/main/js/app/modules/states/configuration/clusters/time.directive.js b/modules/web-console/src/main/js/app/modules/states/configuration/clusters/time.directive.js
deleted file mode 100644
index 8ab3e89..0000000
--- a/modules/web-console/src/main/js/app/modules/states/configuration/clusters/time.directive.js
+++ /dev/null
@@ -1,27 +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 templateUrl from './time.jade';
-
-export default ['igniteConfigurationClustersTime', [() => {
-    return {
-        scope: true,
-        restrict: 'E',
-        templateUrl,
-        replace: true
-    };
-}]];

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/src/main/js/app/modules/states/configuration/clusters/time.jade
----------------------------------------------------------------------
diff --git a/modules/web-console/src/main/js/app/modules/states/configuration/clusters/time.jade b/modules/web-console/src/main/js/app/modules/states/configuration/clusters/time.jade
deleted file mode 100644
index 714a36c..0000000
--- a/modules/web-console/src/main/js/app/modules/states/configuration/clusters/time.jade
+++ /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.
-
-include ../../../../../app/helpers/jade/mixins.jade
-
--var form = 'time'
--var model = 'backupItem'
-
-form.panel.panel-default(name=form novalidate)
-    .panel-heading(bs-collapse-toggle ng-click='ui.loadPanel("#{form}")')
-        ignite-form-panel-chevron
-        label Time configuration
-        ignite-form-field-tooltip.tipLabel
-            | Time settings for CLOCK write ordering mode
-        ignite-form-revert
-    .panel-collapse(role='tabpanel' bs-collapse-target id=form)
-        .panel-body(ng-if='ui.isPanelLoaded("#{form}")')
-            .col-sm-6
-                .settings-row
-                    +number('Samples size:', model + '.clockSyncSamples', 'clockSyncSamples', 'true', '8', '0',
-                        'Number of samples used to synchronize clocks between different nodes<br/>\
-                        Clock synchronization is used for cache version assignment in CLOCK order mode')
-                .settings-row
-                    +number('Frequency:', model + '.clockSyncFrequency', 'clockSyncFrequency', 'true', '120000', '0',
-                        'Frequency at which clock is synchronized between nodes, in milliseconds<br/>\
-                        Clock synchronization is used for cache version assignment in CLOCK order mode')
-                .settings-row
-                    +number-min-max('Port base:', model + '.timeServerPortBase', 'timeServerPortBase', 'true', '31100', '0', '65535',
-                        'Time server provides clock synchronization between nodes<br/>\
-                        Base UPD port number for grid time server. Time server will be started on one of free ports in range')
-                .settings-row
-                    +number('Port range:', model + '.timeServerPortRange', 'timeServerPortRange', 'true', '100', '1', 'Time server port range')
-            .col-sm-6
-                +preview-xml-java(model, 'clusterTime')

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/src/main/js/app/modules/states/configuration/clusters/transactions.directive.js
----------------------------------------------------------------------
diff --git a/modules/web-console/src/main/js/app/modules/states/configuration/clusters/transactions.directive.js b/modules/web-console/src/main/js/app/modules/states/configuration/clusters/transactions.directive.js
deleted file mode 100644
index faca0fa..0000000
--- a/modules/web-console/src/main/js/app/modules/states/configuration/clusters/transactions.directive.js
+++ /dev/null
@@ -1,27 +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 templateUrl from './transactions.jade';
-
-export default ['igniteConfigurationClustersTransactions', [() => {
-    return {
-        scope: true,
-        restrict: 'E',
-        templateUrl,
-        replace: true
-    };
-}]];

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/src/main/js/app/modules/states/configuration/clusters/transactions.jade
----------------------------------------------------------------------
diff --git a/modules/web-console/src/main/js/app/modules/states/configuration/clusters/transactions.jade b/modules/web-console/src/main/js/app/modules/states/configuration/clusters/transactions.jade
deleted file mode 100644
index 3b0fef7..0000000
--- a/modules/web-console/src/main/js/app/modules/states/configuration/clusters/transactions.jade
+++ /dev/null
@@ -1,59 +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.
-
-include ../../../../../app/helpers/jade/mixins.jade
-
--var form = 'transactions'
--var model = 'backupItem.transactionConfiguration'
-
-form.panel.panel-default(name=form novalidate)
-    .panel-heading(bs-collapse-toggle ng-click='ui.loadPanel("#{form}")')
-        ignite-form-panel-chevron
-        label Transactions
-        ignite-form-field-tooltip.tipLabel
-            | Settings for transactions
-        ignite-form-revert
-    .panel-collapse(role='tabpanel' bs-collapse-target id=form)
-        .panel-body(ng-if='ui.isPanelLoaded("#{form}")')
-            .col-sm-6
-                .settings-row
-                    +dropdown('Concurrency:', model + '.defaultTxConcurrency', 'defaultTxConcurrency', 'true', 'PESSIMISTIC',
-                        '[\
-                            {value: "OPTIMISTIC", label: "OPTIMISTIC"},\
-                            {value: "PESSIMISTIC", label: "PESSIMISTIC"}\
-                        ]',
-                        'Cache transaction concurrency to use when one is not explicitly specified')
-                .settings-row
-                    +dropdown('Isolation:', model + '.defaultTxIsolation', 'defaultTxIsolation', 'true', 'REPEATABLE_READ',
-                        '[\
-                            {value: "READ_COMMITTED", label: "READ_COMMITTED"},\
-                            {value: "REPEATABLE_READ", label: "REPEATABLE_READ"},\
-                            {value: "SERIALIZABLE", label: "SERIALIZABLE"}\
-                        ]',
-                        'Default transaction isolation')
-                .settings-row
-                    +number('Default timeout:', model + '.defaultTxTimeout', 'defaultTxTimeout', 'true', '0', '0', 'Default transaction timeout')
-                .settings-row
-                    +number('Pessimistic log cleanup delay:', model + '.pessimisticTxLogLinger', 'pessimisticTxLogLinger', 'true', '10000', '0',
-                        'Delay, in milliseconds, after which pessimistic recovery entries will be cleaned up for failed node')
-                .settings-row
-                    +number('Pessimistic log size:', model + '.pessimisticTxLogSize', 'pessimisticTxLogSize', 'true', '0', '0',
-                        'Size of pessimistic transactions log stored on node in order to recover transaction commit if originating node has left grid before it has sent all messages to transaction nodes')
-                .settings-row
-                    +java-class('Manager factory:', model + '.txManagerFactory', 'txManagerFactory', 'true', 'false',
-                        'Class name of transaction manager factory for integration with JEE app servers')
-            .col-sm-6
-                +preview-xml-java(model, 'clusterTransactions')

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/src/main/js/app/modules/states/configuration/domains/general.directive.js
----------------------------------------------------------------------
diff --git a/modules/web-console/src/main/js/app/modules/states/configuration/domains/general.directive.js b/modules/web-console/src/main/js/app/modules/states/configuration/domains/general.directive.js
deleted file mode 100644
index 9ca02f9..0000000
--- a/modules/web-console/src/main/js/app/modules/states/configuration/domains/general.directive.js
+++ /dev/null
@@ -1,27 +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 templateUrl from './general.jade';
-
-export default ['igniteConfigurationDomainsGeneral', [() => {
-    return {
-        scope: true,
-        restrict: 'E',
-        templateUrl,
-        replace: true
-    };
-}]];


[48/52] ignite git commit: Web Console beta-3. Added execution bit for docker build files.

Posted by ak...@apache.org.
Web Console beta-3. Added execution bit for docker build files.


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

Branch: refs/heads/master
Commit: 492ab120b71a2bd044bb3631560f689c80d8bf95
Parents: 6af6560
Author: Andrey Novikov <an...@apache.org>
Authored: Thu Sep 8 15:16:17 2016 +0700
Committer: Andrey Novikov <an...@apache.org>
Committed: Thu Sep 8 15:16:17 2016 +0700

----------------------------------------------------------------------
 modules/web-console/docker/compose/backend/build.sh  | 0
 modules/web-console/docker/compose/frontend/build.sh | 0
 modules/web-console/docker/standalone/build.sh       | 0
 modules/web-console/docker/standalone/entrypoint.sh  | 0
 4 files changed, 0 insertions(+), 0 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/ignite/blob/492ab120/modules/web-console/docker/compose/backend/build.sh
----------------------------------------------------------------------
diff --git a/modules/web-console/docker/compose/backend/build.sh b/modules/web-console/docker/compose/backend/build.sh
old mode 100644
new mode 100755

http://git-wip-us.apache.org/repos/asf/ignite/blob/492ab120/modules/web-console/docker/compose/frontend/build.sh
----------------------------------------------------------------------
diff --git a/modules/web-console/docker/compose/frontend/build.sh b/modules/web-console/docker/compose/frontend/build.sh
old mode 100644
new mode 100755

http://git-wip-us.apache.org/repos/asf/ignite/blob/492ab120/modules/web-console/docker/standalone/build.sh
----------------------------------------------------------------------
diff --git a/modules/web-console/docker/standalone/build.sh b/modules/web-console/docker/standalone/build.sh
old mode 100644
new mode 100755

http://git-wip-us.apache.org/repos/asf/ignite/blob/492ab120/modules/web-console/docker/standalone/entrypoint.sh
----------------------------------------------------------------------
diff --git a/modules/web-console/docker/standalone/entrypoint.sh b/modules/web-console/docker/standalone/entrypoint.sh
old mode 100644
new mode 100755


[26/52] ignite git commit: Web Console beta-3.

Posted by ak...@apache.org.
http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/frontend/generator/generator-optional.js
----------------------------------------------------------------------
diff --git a/modules/web-console/frontend/generator/generator-optional.js b/modules/web-console/frontend/generator/generator-optional.js
new file mode 100644
index 0000000..61de1a2
--- /dev/null
+++ b/modules/web-console/frontend/generator/generator-optional.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.
+ */
+
+// Optional content generation entry point.
+const $generatorOptional = {};
+
+$generatorOptional.optionalContent = function(zip, cluster) { // eslint-disable-line no-unused-vars
+    // No-op.
+};
+
+export default $generatorOptional;

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/frontend/generator/generator-properties.js
----------------------------------------------------------------------
diff --git a/modules/web-console/frontend/generator/generator-properties.js b/modules/web-console/frontend/generator/generator-properties.js
new file mode 100644
index 0000000..9d1e7e3
--- /dev/null
+++ b/modules/web-console/frontend/generator/generator-properties.js
@@ -0,0 +1,175 @@
+/*
+ * 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.
+ */
+
+// Properties generation entry point.
+const $generatorProperties = {};
+
+$generatorProperties.jdbcUrlTemplate = function(dialect) {
+    switch (dialect) {
+        case 'Oracle':
+            return 'jdbc:oracle:thin:@[host]:[port]:[database]';
+        case 'DB2':
+            return 'jdbc:db2://[host]:[port]/[database]';
+        case 'SQLServer':
+            return 'jdbc:sqlserver://[host]:[port][;databaseName=database]';
+        case 'MySQL':
+            return 'jdbc:mysql://[host]:[port]/[database]';
+        case 'PostgreSQL':
+            return 'jdbc:postgresql://[host]:[port]/[database]';
+        case 'H2':
+            return 'jdbc:h2:tcp://[host]/[database]';
+        default:
+    }
+
+    return 'jdbc:your_database';
+};
+
+$generatorProperties.createBuilder = function() {
+    const res = $generatorCommon.builder();
+
+    res.line('# ' + $generatorCommon.mainComment());
+
+    return res;
+};
+
+/**
+ * Generate properties file with properties stubs for stores data sources.
+ *
+ * @param res Resulting output with generated properties.
+ * @param datasources Already added datasources.
+ * @param storeFactory Current datasource factory.
+ * @param dialect Current dialect.
+ * @returns {string} Generated content.
+ */
+$generatorProperties.dataSourceProperties = function(res, datasources, storeFactory, dialect) {
+    const beanId = storeFactory.dataSourceBean;
+
+    const dsClsName = $generatorCommon.dataSourceClassName(dialect);
+
+    const varType = res.importClass(dsClsName);
+
+    const beanClassName = $generatorCommon.toJavaName(varType, storeFactory.dataSourceBean);
+
+    if (!_.includes(datasources, beanClassName)) {
+        datasources.push(beanClassName);
+
+        res.needEmptyLine = true;
+
+        switch (dialect) {
+            case 'DB2':
+                res.line(beanId + '.jdbc.server_name=YOUR_DATABASE_SERVER_NAME');
+                res.line(beanId + '.jdbc.port_number=YOUR_JDBC_PORT_NUMBER');
+                res.line(beanId + '.jdbc.driver_type=YOUR_JDBC_DRIVER_TYPE');
+                res.line(beanId + '.jdbc.database_name=YOUR_DATABASE_NAME');
+
+                break;
+
+            default:
+                res.line(beanId + '.jdbc.url=' + $generatorProperties.jdbcUrlTemplate(dialect));
+        }
+
+        res.line(beanId + '.jdbc.username=YOUR_USER_NAME');
+        res.line(beanId + '.jdbc.password=YOUR_PASSWORD');
+        res.line('');
+    }
+};
+
+/**
+ * Generate properties file with properties stubs for stores data sources.
+ *
+ * @param cluster Configuration to process.
+ * @param res Resulting output with generated properties.
+ * @returns {string} Generated content.
+ */
+$generatorProperties.dataSourcesProperties = function(cluster, res) {
+    const datasources = [];
+
+    if (cluster.caches && cluster.caches.length > 0) {
+        _.forEach(cluster.caches, function(cache) {
+            if (cache.cacheStoreFactory && cache.cacheStoreFactory.kind) {
+                const storeFactory = cache.cacheStoreFactory[cache.cacheStoreFactory.kind];
+
+                const dialect = storeFactory.connectVia ? (storeFactory.connectVia === 'DataSource' ? storeFactory.dialect : null) : storeFactory.dialect;
+
+                const connectViaUrl = cache.cacheStoreFactory.kind === 'CacheJdbcBlobStoreFactory' && storeFactory.connectVia === 'URL';
+
+                if (!res && (dialect || connectViaUrl))
+                    res = $generatorProperties.createBuilder();
+
+                if (dialect)
+                    $generatorProperties.dataSourceProperties(res, datasources, storeFactory, dialect);
+
+                if (connectViaUrl)
+                    res.line('ds.' + storeFactory.user + '.password=YOUR_PASSWORD');
+            }
+        });
+    }
+
+    if (cluster.discovery.kind === 'Jdbc') {
+        const ds = cluster.discovery.Jdbc;
+
+        if (ds.dataSourceBean && ds.dialect) {
+            if (!res)
+                res = $generatorProperties.createBuilder();
+
+            $generatorProperties.dataSourceProperties(res, datasources, ds, ds.dialect);
+        }
+    }
+
+    return res;
+};
+
+/**
+ * Generate properties file with properties stubs for cluster SSL configuration.
+ *
+ * @param cluster Cluster to get SSL configuration.
+ * @param res Optional configuration presentation builder object.
+ * @returns Configuration presentation builder object
+ */
+$generatorProperties.sslProperties = function(cluster, res) {
+    if (cluster.sslEnabled && cluster.sslContextFactory) {
+        if (!res)
+            res = $generatorProperties.createBuilder();
+
+        res.needEmptyLine = true;
+
+        if (_.isEmpty(cluster.sslContextFactory.keyStoreFilePath))
+            res.line('ssl.key.storage.password=YOUR_SSL_KEY_STORAGE_PASSWORD');
+
+        if (_.isEmpty(cluster.sslContextFactory.trustStoreFilePath))
+            res.line('ssl.trust.storage.password=YOUR_SSL_TRUST_STORAGE_PASSWORD');
+    }
+
+    return res;
+};
+
+/**
+ * Generate properties file with all possible properties.
+ *
+ * @param cluster Cluster to get configurations.
+ * @param res Optional configuration presentation builder object.
+ * @returns Configuration presentation builder object
+ */
+$generatorProperties.generateProperties = function(cluster, res) {
+    res = $generatorProperties.dataSourcesProperties(cluster, res);
+
+    res = $generatorProperties.sslProperties(cluster, res);
+
+    return res;
+};
+
+export default $generatorProperties;

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/frontend/generator/generator-readme.js
----------------------------------------------------------------------
diff --git a/modules/web-console/frontend/generator/generator-readme.js b/modules/web-console/frontend/generator/generator-readme.js
new file mode 100644
index 0000000..432f1e6
--- /dev/null
+++ b/modules/web-console/frontend/generator/generator-readme.js
@@ -0,0 +1,85 @@
+/*
+ * 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.
+ */
+
+// README.txt generation entry point.
+const $generatorReadme = {};
+
+$generatorReadme.generatedBy = function(res) {
+    res.line('Content of this folder was generated by Apache Ignite Web Console');
+    res.line('=================================================================');
+
+    res.needEmptyLine = true;
+};
+
+/**
+ * Generate README.txt.
+ *
+ * @param res Resulting output with generated readme.
+ * @returns {string} Generated content.
+ */
+$generatorReadme.readme = function(res) {
+    if (!res)
+        res = $generatorCommon.builder();
+
+    $generatorReadme.generatedBy(res);
+
+    res.line('Project structure:');
+    res.line('    /config - this folder contains client and server XML configurations.');
+    res.line('    /jdbc-drivers - this folder should contains proprietary JDBC drivers.');
+    res.line('    /src - this folder contains generated java code.');
+    res.line('    /src/main/java/config - this folder contains generated java classes with cluster configuration from code.');
+    res.line('    /src/main/java/startup - this folder contains generated java classes with server and client nodes startup code.');
+    res.line('    /src/main/java/[model] - this optional folder will be named as package name for your POJO classes and contain generated POJO files.');
+    res.line('    /src/main/resources - this optional folder contains generated secret.properties file with security sensitive information if any.');
+    res.line('    Dockerfile - sample Docker file. With this file you could package Ignite deployment with all the dependencies into a standard container.');
+    res.line('    pom.xml - generated Maven project description, could be used to open generated project in IDE or build with Maven.');
+    res.line('    README.txt - this file.');
+
+    res.needEmptyLine = true;
+
+    res.line('Ignite ships with CacheJdbcPojoStore, which is out-of-the-box JDBC implementation of the IgniteCacheStore ');
+    res.line('interface, and automatically handles all the write-through and read-through logic.');
+
+    res.needEmptyLine = true;
+
+    res.line('You can use generated configuration and POJO classes as part of your application.');
+
+    res.needEmptyLine = true;
+
+    res.line('Note, in case of using proprietary JDBC drivers (Oracle, IBM DB2, Microsoft SQL Server)');
+    res.line('you should download them manually and copy into ./jdbc-drivers folder.');
+
+    return res;
+};
+
+/**
+ * Generate README.txt for jdbc folder.
+ *
+ * @param res Resulting output with generated readme.
+ * @returns {string} Generated content.
+ */
+$generatorReadme.readmeJdbc = function(res) {
+    if (!res)
+        res = $generatorCommon.builder();
+
+    res.line('Proprietary JDBC drivers for databases like Oracle, IBM DB2, Microsoft SQL Server are not available on Maven Central repository.');
+    res.line('Drivers should be downloaded manually and copied to this folder.');
+
+    return res;
+};
+
+export default $generatorReadme;

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/frontend/generator/generator-xml.js
----------------------------------------------------------------------
diff --git a/modules/web-console/frontend/generator/generator-xml.js b/modules/web-console/frontend/generator/generator-xml.js
new file mode 100644
index 0000000..b49b052
--- /dev/null
+++ b/modules/web-console/frontend/generator/generator-xml.js
@@ -0,0 +1,2093 @@
+/*
+ * 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.
+ */
+
+// XML generation entry point.
+const $generatorXml = {};
+
+// Do XML escape.
+$generatorXml.escape = function(s) {
+    if (typeof (s) !== 'string')
+        return s;
+
+    return s.replace(/&/g, '&amp;').replace(/</g, '&lt;').replace(/>/g, '&gt;').replace(/"/g, '&quot;');
+};
+
+// Add constructor argument
+$generatorXml.constructorArg = function(res, ix, obj, propName, dflt, opt) {
+    const v = (obj ? obj[propName] : null) || dflt;
+
+    if ($generatorCommon.isDefinedAndNotEmpty(v))
+        res.line('<constructor-arg ' + (ix >= 0 ? 'index="' + ix + '" ' : '') + 'value="' + v + '"/>');
+    else if (!opt) {
+        res.startBlock('<constructor-arg ' + (ix >= 0 ? 'index="' + ix + '"' : '') + '>');
+        res.line('<null/>');
+        res.endBlock('</constructor-arg>');
+    }
+};
+
+// Add XML element.
+$generatorXml.element = function(res, tag, attr1, val1, attr2, val2) {
+    let elem = '<' + tag;
+
+    if (attr1)
+        elem += ' ' + attr1 + '="' + val1 + '"';
+
+    if (attr2)
+        elem += ' ' + attr2 + '="' + val2 + '"';
+
+    elem += '/>';
+
+    res.emptyLineIfNeeded();
+    res.line(elem);
+};
+
+// Add property.
+$generatorXml.property = function(res, obj, propName, setterName, dflt) {
+    if (!_.isNil(obj)) {
+        const val = obj[propName];
+
+        if ($generatorCommon.isDefinedAndNotEmpty(val)) {
+            const missDflt = _.isNil(dflt);
+
+            // Add to result if no default provided or value not equals to default.
+            if (missDflt || (!missDflt && val !== dflt)) {
+                $generatorXml.element(res, 'property', 'name', setterName ? setterName : propName, 'value', $generatorXml.escape(val));
+
+                return true;
+            }
+        }
+    }
+
+    return false;
+};
+
+// Add property for class name.
+$generatorXml.classNameProperty = function(res, obj, propName) {
+    const val = obj[propName];
+
+    if (!_.isNil(val))
+        $generatorXml.element(res, 'property', 'name', propName, 'value', $generatorCommon.JavaTypes.fullClassName(val));
+};
+
+// Add list property.
+$generatorXml.listProperty = function(res, obj, propName, listType, rowFactory) {
+    const val = obj[propName];
+
+    if (val && val.length > 0) {
+        res.emptyLineIfNeeded();
+
+        if (!listType)
+            listType = 'list';
+
+        if (!rowFactory)
+            rowFactory = (v) => '<value>' + $generatorXml.escape(v) + '</value>';
+
+        res.startBlock('<property name="' + propName + '">');
+        res.startBlock('<' + listType + '>');
+
+        _.forEach(val, (v) => res.line(rowFactory(v)));
+
+        res.endBlock('</' + listType + '>');
+        res.endBlock('</property>');
+
+        res.needEmptyLine = true;
+    }
+};
+
+// Add array property
+$generatorXml.arrayProperty = function(res, obj, propName, descr, rowFactory) {
+    const val = obj[propName];
+
+    if (val && val.length > 0) {
+        res.emptyLineIfNeeded();
+
+        if (!rowFactory)
+            rowFactory = (v) => '<bean class="' + v + '"/>';
+
+        res.startBlock('<property name="' + propName + '">');
+        res.startBlock('<list>');
+
+        _.forEach(val, (v) => res.append(rowFactory(v)));
+
+        res.endBlock('</list>');
+        res.endBlock('</property>');
+    }
+};
+
+/**
+ * Add bean property with internal content.
+ *
+ * @param res Optional configuration presentation builder object.
+ * @param bean Bean object for code generation.
+ * @param beanPropName Name of property to set generated bean as value.
+ * @param desc Bean metadata object.
+ * @param createBeanAlthoughNoProps Always generate bean even it has no properties defined.
+ */
+$generatorXml.beanProperty = function(res, bean, beanPropName, desc, createBeanAlthoughNoProps) {
+    const props = desc.fields;
+
+    if (bean && $generatorCommon.hasProperty(bean, props)) {
+        if (!createBeanAlthoughNoProps)
+            res.startSafeBlock();
+
+        res.emptyLineIfNeeded();
+        res.startBlock('<property name="' + beanPropName + '">');
+
+        if (createBeanAlthoughNoProps)
+            res.startSafeBlock();
+
+        res.startBlock('<bean class="' + desc.className + '">');
+
+        let hasData = false;
+
+        _.forIn(props, function(descr, propName) {
+            if (props.hasOwnProperty(propName)) {
+                if (descr) {
+                    switch (descr.type) {
+                        case 'list':
+                            $generatorXml.listProperty(res, bean, propName, descr.setterName);
+
+                            break;
+
+                        case 'array':
+                            $generatorXml.arrayProperty(res, bean, propName, descr);
+
+                            break;
+
+                        case 'propertiesAsList':
+                            const val = bean[propName];
+
+                            if (val && val.length > 0) {
+                                res.startBlock('<property name="' + propName + '">');
+                                res.startBlock('<props>');
+
+                                _.forEach(val, function(nameAndValue) {
+                                    const eqIndex = nameAndValue.indexOf('=');
+                                    if (eqIndex >= 0) {
+                                        res.line('<prop key="' + $generatorXml.escape(nameAndValue.substring(0, eqIndex)) + '">' +
+                                            $generatorXml.escape(nameAndValue.substr(eqIndex + 1)) + '</prop>');
+                                    }
+                                });
+
+                                res.endBlock('</props>');
+                                res.endBlock('</property>');
+
+                                hasData = true;
+                            }
+
+                            break;
+
+                        case 'bean':
+                            if ($generatorCommon.isDefinedAndNotEmpty(bean[propName])) {
+                                res.startBlock('<property name="' + propName + '">');
+                                res.line('<bean class="' + bean[propName] + '"/>');
+                                res.endBlock('</property>');
+
+                                hasData = true;
+                            }
+
+                            break;
+
+                        default:
+                            if ($generatorXml.property(res, bean, propName, descr.setterName, descr.dflt))
+                                hasData = true;
+                    }
+                }
+                else
+                    if ($generatorXml.property(res, bean, propName))
+                        hasData = true;
+            }
+        });
+
+        res.endBlock('</bean>');
+
+        if (createBeanAlthoughNoProps && !hasData) {
+            res.rollbackSafeBlock();
+
+            res.line('<bean class="' + desc.className + '"/>');
+        }
+
+        res.endBlock('</property>');
+
+        if (!createBeanAlthoughNoProps && !hasData)
+            res.rollbackSafeBlock();
+    }
+    else if (createBeanAlthoughNoProps) {
+        res.emptyLineIfNeeded();
+        res.startBlock('<property name="' + beanPropName + '">');
+        res.line('<bean class="' + desc.className + '"/>');
+        res.endBlock('</property>');
+    }
+};
+
+/**
+ * Add bean property without internal content.
+ *
+ * @param res Optional configuration presentation builder object.
+ * @param obj Object to take bean class name.
+ * @param propName Property name.
+ */
+$generatorXml.simpleBeanProperty = function(res, obj, propName) {
+    if (!_.isNil(obj)) {
+        const val = obj[propName];
+
+        if ($generatorCommon.isDefinedAndNotEmpty(val)) {
+            res.startBlock('<property name="' + propName + '">');
+            res.line('<bean class="' + val + '"/>');
+            res.endBlock('</property>');
+        }
+    }
+
+    return false;
+};
+
+// Generate eviction policy.
+$generatorXml.evictionPolicy = function(res, evtPlc, propName) {
+    if (evtPlc && evtPlc.kind) {
+        $generatorXml.beanProperty(res, evtPlc[evtPlc.kind.toUpperCase()], propName,
+            $generatorCommon.EVICTION_POLICIES[evtPlc.kind], true);
+    }
+};
+
+// Generate discovery.
+$generatorXml.clusterGeneral = function(cluster, res) {
+    if (!res)
+        res = $generatorCommon.builder();
+
+    $generatorXml.property(res, cluster, 'name', 'gridName');
+    $generatorXml.property(res, cluster, 'localHost');
+
+    if (cluster.discovery) {
+        res.startBlock('<property name="discoverySpi">');
+        res.startBlock('<bean class="org.apache.ignite.spi.discovery.tcp.TcpDiscoverySpi">');
+        res.startBlock('<property name="ipFinder">');
+
+        const d = cluster.discovery;
+
+        switch (d.kind) {
+            case 'Multicast':
+                res.startBlock('<bean class="org.apache.ignite.spi.discovery.tcp.ipfinder.multicast.TcpDiscoveryMulticastIpFinder">');
+
+                if (d.Multicast) {
+                    $generatorXml.property(res, d.Multicast, 'multicastGroup');
+                    $generatorXml.property(res, d.Multicast, 'multicastPort');
+                    $generatorXml.property(res, d.Multicast, 'responseWaitTime');
+                    $generatorXml.property(res, d.Multicast, 'addressRequestAttempts');
+                    $generatorXml.property(res, d.Multicast, 'localAddress');
+                    $generatorXml.listProperty(res, d.Multicast, 'addresses');
+                }
+
+                res.endBlock('</bean>');
+
+                break;
+
+            case 'Vm':
+                res.startBlock('<bean class="org.apache.ignite.spi.discovery.tcp.ipfinder.vm.TcpDiscoveryVmIpFinder">');
+
+                if (d.Vm)
+                    $generatorXml.listProperty(res, d.Vm, 'addresses');
+
+                res.endBlock('</bean>');
+
+                break;
+
+            case 'S3':
+                res.startBlock('<bean class="org.apache.ignite.spi.discovery.tcp.ipfinder.s3.TcpDiscoveryS3IpFinder">');
+
+                if (d.S3) {
+                    if (d.S3.bucketName)
+                        res.line('<property name="bucketName" value="' + $generatorXml.escape(d.S3.bucketName) + '"/>');
+                }
+
+                res.endBlock('</bean>');
+
+                break;
+
+            case 'Cloud':
+                res.startBlock('<bean class="org.apache.ignite.spi.discovery.tcp.ipfinder.cloud.TcpDiscoveryCloudIpFinder">');
+
+                if (d.Cloud) {
+                    $generatorXml.property(res, d.Cloud, 'credential');
+                    $generatorXml.property(res, d.Cloud, 'credentialPath');
+                    $generatorXml.property(res, d.Cloud, 'identity');
+                    $generatorXml.property(res, d.Cloud, 'provider');
+                    $generatorXml.listProperty(res, d.Cloud, 'regions');
+                    $generatorXml.listProperty(res, d.Cloud, 'zones');
+                }
+
+                res.endBlock('</bean>');
+
+                break;
+
+            case 'GoogleStorage':
+                res.startBlock('<bean class="org.apache.ignite.spi.discovery.tcp.ipfinder.gce.TcpDiscoveryGoogleStorageIpFinder">');
+
+                if (d.GoogleStorage) {
+                    $generatorXml.property(res, d.GoogleStorage, 'projectName');
+                    $generatorXml.property(res, d.GoogleStorage, 'bucketName');
+                    $generatorXml.property(res, d.GoogleStorage, 'serviceAccountP12FilePath');
+                    $generatorXml.property(res, d.GoogleStorage, 'serviceAccountId');
+                }
+
+                res.endBlock('</bean>');
+
+                break;
+
+            case 'Jdbc':
+                res.startBlock('<bean class="org.apache.ignite.spi.discovery.tcp.ipfinder.jdbc.TcpDiscoveryJdbcIpFinder">');
+
+                if (d.Jdbc) {
+                    const datasource = d.Jdbc;
+
+                    res.line('<property name="initSchema" value="' + (!_.isNil(datasource.initSchema) && datasource.initSchema) + '"/>');
+
+                    if (datasource.dataSourceBean && datasource.dialect) {
+                        res.line('<property name="dataSource" ref="' + datasource.dataSourceBean + '"/>');
+
+                        if (_.findIndex(res.datasources, (ds) => ds.dataSourceBean === datasource.dataSourceBean) < 0) {
+                            res.datasources.push({
+                                dataSourceBean: datasource.dataSourceBean,
+                                dialect: datasource.dialect
+                            });
+                        }
+                    }
+                }
+
+                res.endBlock('</bean>');
+
+                break;
+
+            case 'SharedFs':
+                res.startBlock('<bean class="org.apache.ignite.spi.discovery.tcp.ipfinder.sharedfs.TcpDiscoverySharedFsIpFinder">');
+
+                if (d.SharedFs)
+                    $generatorXml.property(res, d.SharedFs, 'path');
+
+                res.endBlock('</bean>');
+
+                break;
+
+            case 'ZooKeeper':
+                res.startBlock('<bean class="org.apache.ignite.spi.discovery.tcp.ipfinder.zk.TcpDiscoveryZookeeperIpFinder">');
+
+                if (d.ZooKeeper) {
+                    if ($generatorCommon.isDefinedAndNotEmpty(d.ZooKeeper.curator)) {
+                        res.startBlock('<property name="curator">');
+                        res.line('<bean class="' + d.ZooKeeper.curator + '"/>');
+                        res.endBlock('</property>');
+                    }
+
+                    $generatorXml.property(res, d.ZooKeeper, 'zkConnectionString');
+
+                    if (d.ZooKeeper.retryPolicy && d.ZooKeeper.retryPolicy.kind) {
+                        const kind = d.ZooKeeper.retryPolicy.kind;
+                        const retryPolicy = d.ZooKeeper.retryPolicy[kind];
+                        const customClassDefined = retryPolicy && $generatorCommon.isDefinedAndNotEmpty(retryPolicy.className);
+
+                        if (kind !== 'Custom' || customClassDefined)
+                            res.startBlock('<property name="retryPolicy">');
+
+                        switch (kind) {
+                            case 'ExponentialBackoff':
+                                res.startBlock('<bean class="org.apache.curator.retry.ExponentialBackoffRetry">');
+                                $generatorXml.constructorArg(res, 0, retryPolicy, 'baseSleepTimeMs', 1000);
+                                $generatorXml.constructorArg(res, 1, retryPolicy, 'maxRetries', 10);
+                                $generatorXml.constructorArg(res, 2, retryPolicy, 'maxSleepMs', null, true);
+                                res.endBlock('</bean>');
+
+                                break;
+
+                            case 'BoundedExponentialBackoff':
+                                res.startBlock('<bean class="org.apache.curator.retry.BoundedExponentialBackoffRetry">');
+                                $generatorXml.constructorArg(res, 0, retryPolicy, 'baseSleepTimeMs', 1000);
+                                $generatorXml.constructorArg(res, 1, retryPolicy, 'maxSleepTimeMs', 2147483647);
+                                $generatorXml.constructorArg(res, 2, retryPolicy, 'maxRetries', 10);
+                                res.endBlock('</bean>');
+
+                                break;
+
+                            case 'UntilElapsed':
+                                res.startBlock('<bean class="org.apache.curator.retry.RetryUntilElapsed">');
+                                $generatorXml.constructorArg(res, 0, retryPolicy, 'maxElapsedTimeMs', 60000);
+                                $generatorXml.constructorArg(res, 1, retryPolicy, 'sleepMsBetweenRetries', 1000);
+                                res.endBlock('</bean>');
+
+                                break;
+
+                            case 'NTimes':
+                                res.startBlock('<bean class="org.apache.curator.retry.RetryNTimes">');
+                                $generatorXml.constructorArg(res, 0, retryPolicy, 'n', 10);
+                                $generatorXml.constructorArg(res, 1, retryPolicy, 'sleepMsBetweenRetries', 1000);
+                                res.endBlock('</bean>');
+
+                                break;
+
+                            case 'OneTime':
+                                res.startBlock('<bean class="org.apache.curator.retry.RetryOneTime">');
+                                $generatorXml.constructorArg(res, 0, retryPolicy, 'sleepMsBetweenRetry', 1000);
+                                res.endBlock('</bean>');
+
+                                break;
+
+                            case 'Forever':
+                                res.startBlock('<bean class="org.apache.curator.retry.RetryForever">');
+                                $generatorXml.constructorArg(res, 0, retryPolicy, 'retryIntervalMs', 1000);
+                                res.endBlock('</bean>');
+
+                                break;
+
+                            case 'Custom':
+                                if (customClassDefined)
+                                    res.line('<bean class="' + retryPolicy.className + '"/>');
+
+                                break;
+
+                            default:
+                        }
+
+                        if (kind !== 'Custom' || customClassDefined)
+                            res.endBlock('</property>');
+                    }
+
+                    $generatorXml.property(res, d.ZooKeeper, 'basePath', null, '/services');
+                    $generatorXml.property(res, d.ZooKeeper, 'serviceName', null, 'ignite');
+                    $generatorXml.property(res, d.ZooKeeper, 'allowDuplicateRegistrations', null, false);
+                }
+
+                res.endBlock('</bean>');
+
+                break;
+
+            default:
+                res.line('Unknown discovery kind: ' + d.kind);
+        }
+
+        res.endBlock('</property>');
+
+        $generatorXml.clusterDiscovery(d, res);
+
+        res.endBlock('</bean>');
+        res.endBlock('</property>');
+
+        res.needEmptyLine = true;
+    }
+
+    return res;
+};
+
+// Generate atomics group.
+$generatorXml.clusterAtomics = function(atomics, res) {
+    if (!res)
+        res = $generatorCommon.builder();
+
+    if ($generatorCommon.hasAtLeastOneProperty(atomics, ['cacheMode', 'atomicSequenceReserveSize', 'backups'])) {
+        res.startSafeBlock();
+
+        res.emptyLineIfNeeded();
+
+        res.startBlock('<property name="atomicConfiguration">');
+        res.startBlock('<bean class="org.apache.ignite.configuration.AtomicConfiguration">');
+
+        const cacheMode = atomics.cacheMode ? atomics.cacheMode : 'PARTITIONED';
+
+        let hasData = cacheMode !== 'PARTITIONED';
+
+        $generatorXml.property(res, atomics, 'cacheMode', null, 'PARTITIONED');
+
+        hasData = $generatorXml.property(res, atomics, 'atomicSequenceReserveSize', null, 1000) || hasData;
+
+        if (cacheMode === 'PARTITIONED')
+            hasData = $generatorXml.property(res, atomics, 'backups', null, 0) || hasData;
+
+        res.endBlock('</bean>');
+        res.endBlock('</property>');
+
+        res.needEmptyLine = true;
+
+        if (!hasData)
+            res.rollbackSafeBlock();
+    }
+
+    return res;
+};
+
+// Generate binary group.
+$generatorXml.clusterBinary = function(binary, res) {
+    if (!res)
+        res = $generatorCommon.builder();
+
+    if ($generatorCommon.binaryIsDefined(binary)) {
+        res.startBlock('<property name="binaryConfiguration">');
+        res.startBlock('<bean class="org.apache.ignite.configuration.BinaryConfiguration">');
+
+        $generatorXml.simpleBeanProperty(res, binary, 'idMapper');
+        $generatorXml.simpleBeanProperty(res, binary, 'nameMapper');
+        $generatorXml.simpleBeanProperty(res, binary, 'serializer');
+
+        if ($generatorCommon.isDefinedAndNotEmpty(binary.typeConfigurations)) {
+            res.startBlock('<property name="typeConfigurations">');
+            res.startBlock('<list>');
+
+            _.forEach(binary.typeConfigurations, function(type) {
+                res.startBlock('<bean class="org.apache.ignite.binary.BinaryTypeConfiguration">');
+
+                $generatorXml.property(res, type, 'typeName');
+                $generatorXml.simpleBeanProperty(res, type, 'idMapper');
+                $generatorXml.simpleBeanProperty(res, type, 'nameMapper');
+                $generatorXml.simpleBeanProperty(res, type, 'serializer');
+                $generatorXml.property(res, type, 'enum', null, false);
+
+                res.endBlock('</bean>');
+            });
+
+            res.endBlock('</list>');
+            res.endBlock('</property>');
+        }
+
+        $generatorXml.property(res, binary, 'compactFooter', null, true);
+
+        res.endBlock('</bean>');
+        res.endBlock('</property>');
+
+        res.needEmptyLine = true;
+    }
+
+    return res;
+};
+
+// Generate cache key configurations.
+$generatorXml.clusterCacheKeyConfiguration = function(keyCfgs, res) {
+    if (!res)
+        res = $generatorCommon.builder();
+
+    keyCfgs = _.filter(keyCfgs, (cfg) => cfg.typeName && cfg.affinityKeyFieldName);
+
+    if (_.isEmpty(keyCfgs))
+        return res;
+
+    res.startBlock('<property name="cacheKeyConfiguration">');
+    res.startBlock('<array>');
+
+    _.forEach(keyCfgs, (cfg) => {
+        res.startBlock('<bean class="org.apache.ignite.cache.CacheKeyConfiguration">');
+
+        $generatorXml.constructorArg(res, -1, cfg, 'typeName');
+        $generatorXml.constructorArg(res, -1, cfg, 'affinityKeyFieldName');
+
+        res.endBlock('</bean>');
+    });
+
+    res.endBlock('</array>');
+    res.endBlock('</property>');
+
+    return res;
+};
+
+// Generate collision group.
+$generatorXml.clusterCollision = function(collision, res) {
+    if (!res)
+        res = $generatorCommon.builder();
+
+    if (collision && collision.kind && collision.kind !== 'Noop') {
+        const spi = collision[collision.kind];
+
+        if (collision.kind !== 'Custom' || (spi && $generatorCommon.isDefinedAndNotEmpty(spi.class))) {
+            res.startBlock('<property name="collisionSpi">');
+
+            switch (collision.kind) {
+                case 'JobStealing':
+                    res.startBlock('<bean class="org.apache.ignite.spi.collision.jobstealing.JobStealingCollisionSpi">');
+                    $generatorXml.property(res, spi, 'activeJobsThreshold', null, 95);
+                    $generatorXml.property(res, spi, 'waitJobsThreshold', null, 0);
+                    $generatorXml.property(res, spi, 'messageExpireTime', null, 1000);
+                    $generatorXml.property(res, spi, 'maximumStealingAttempts', null, 5);
+                    $generatorXml.property(res, spi, 'stealingEnabled', null, true);
+
+                    if ($generatorCommon.isDefinedAndNotEmpty(spi.externalCollisionListener)) {
+                        res.needEmptyLine = true;
+
+                        res.startBlock('<property name="externalCollisionListener">');
+                        res.line('<bean class="' + spi.externalCollisionListener + ' "/>');
+                        res.endBlock('</property>');
+                    }
+
+                    if ($generatorCommon.isDefinedAndNotEmpty(spi.stealingAttributes)) {
+                        res.needEmptyLine = true;
+
+                        res.startBlock('<property name="stealingAttributes">');
+                        res.startBlock('<map>');
+
+                        _.forEach(spi.stealingAttributes, function(attr) {
+                            $generatorXml.element(res, 'entry', 'key', attr.name, 'value', attr.value);
+                        });
+
+                        res.endBlock('</map>');
+                        res.endBlock('</property>');
+                    }
+
+                    res.endBlock('</bean>');
+
+                    break;
+
+                case 'FifoQueue':
+                    res.startBlock('<bean class="org.apache.ignite.spi.collision.fifoqueue.FifoQueueCollisionSpi">');
+                    $generatorXml.property(res, spi, 'parallelJobsNumber');
+                    $generatorXml.property(res, spi, 'waitingJobsNumber');
+                    res.endBlock('</bean>');
+
+                    break;
+
+                case 'PriorityQueue':
+                    res.startBlock('<bean class="org.apache.ignite.spi.collision.priorityqueue.PriorityQueueCollisionSpi">');
+                    $generatorXml.property(res, spi, 'parallelJobsNumber');
+                    $generatorXml.property(res, spi, 'waitingJobsNumber');
+                    $generatorXml.property(res, spi, 'priorityAttributeKey', null, 'grid.task.priority');
+                    $generatorXml.property(res, spi, 'jobPriorityAttributeKey', null, 'grid.job.priority');
+                    $generatorXml.property(res, spi, 'defaultPriority', null, 0);
+                    $generatorXml.property(res, spi, 'starvationIncrement', null, 1);
+                    $generatorXml.property(res, spi, 'starvationPreventionEnabled', null, true);
+                    res.endBlock('</bean>');
+
+                    break;
+
+                case 'Custom':
+                    res.line('<bean class="' + spi.class + '"/>');
+
+                    break;
+
+                default:
+            }
+
+            res.endBlock('</property>');
+        }
+    }
+
+    return res;
+};
+
+// Generate communication group.
+$generatorXml.clusterCommunication = function(cluster, res) {
+    if (!res)
+        res = $generatorCommon.builder();
+
+    $generatorXml.beanProperty(res, cluster.communication, 'communicationSpi', $generatorCommon.COMMUNICATION_CONFIGURATION);
+
+    $generatorXml.property(res, cluster, 'networkTimeout', null, 5000);
+    $generatorXml.property(res, cluster, 'networkSendRetryDelay', null, 1000);
+    $generatorXml.property(res, cluster, 'networkSendRetryCount', null, 3);
+    $generatorXml.property(res, cluster, 'segmentCheckFrequency');
+    $generatorXml.property(res, cluster, 'waitForSegmentOnStart', null, false);
+    $generatorXml.property(res, cluster, 'discoveryStartupDelay', null, 60000);
+
+    res.needEmptyLine = true;
+
+    return res;
+};
+
+/**
+ * XML generator for cluster's REST access configuration.
+ *
+ * @param connector Cluster REST connector configuration.
+ * @param res Optional configuration presentation builder object.
+ * @returns Configuration presentation builder object
+ */
+$generatorXml.clusterConnector = function(connector, res) {
+    if (!res)
+        res = $generatorCommon.builder();
+
+    if (!_.isNil(connector) && connector.enabled) {
+        const cfg = _.cloneDeep($generatorCommon.CONNECTOR_CONFIGURATION);
+
+        if (connector.sslEnabled) {
+            cfg.fields.sslClientAuth = {dflt: false};
+            cfg.fields.sslFactory = {type: 'bean'};
+        }
+
+        $generatorXml.beanProperty(res, connector, 'connectorConfiguration', cfg, true);
+
+        res.needEmptyLine = true;
+    }
+
+    return res;
+};
+
+// Generate deployment group.
+$generatorXml.clusterDeployment = function(cluster, res) {
+    if (!res)
+        res = $generatorCommon.builder();
+
+    if ($generatorXml.property(res, cluster, 'deploymentMode', null, 'SHARED'))
+        res.needEmptyLine = true;
+
+    const p2pEnabled = cluster.peerClassLoadingEnabled;
+
+    if (!_.isNil(p2pEnabled)) {
+        $generatorXml.property(res, cluster, 'peerClassLoadingEnabled', null, false);
+
+        if (p2pEnabled) {
+            $generatorXml.property(res, cluster, 'peerClassLoadingMissedResourcesCacheSize', null, 100);
+            $generatorXml.property(res, cluster, 'peerClassLoadingThreadPoolSize', null, 2);
+            $generatorXml.listProperty(res, cluster, 'peerClassLoadingLocalClassPathExclude');
+        }
+
+        res.needEmptyLine = true;
+    }
+
+    return res;
+};
+
+// Generate discovery group.
+$generatorXml.clusterDiscovery = function(disco, res) {
+    if (!res)
+        res = $generatorCommon.builder();
+
+    if (disco) {
+        $generatorXml.property(res, disco, 'localAddress');
+        $generatorXml.property(res, disco, 'localPort', null, 47500);
+        $generatorXml.property(res, disco, 'localPortRange', null, 100);
+        if ($generatorCommon.isDefinedAndNotEmpty(disco.addressResolver))
+            $generatorXml.beanProperty(res, disco, 'addressResolver', {className: disco.addressResolver}, true);
+        $generatorXml.property(res, disco, 'socketTimeout', null, 5000);
+        $generatorXml.property(res, disco, 'ackTimeout', null, 5000);
+        $generatorXml.property(res, disco, 'maxAckTimeout', null, 600000);
+        $generatorXml.property(res, disco, 'networkTimeout', null, 5000);
+        $generatorXml.property(res, disco, 'joinTimeout', null, 0);
+        $generatorXml.property(res, disco, 'threadPriority', null, 10);
+        $generatorXml.property(res, disco, 'heartbeatFrequency', null, 2000);
+        $generatorXml.property(res, disco, 'maxMissedHeartbeats', null, 1);
+        $generatorXml.property(res, disco, 'maxMissedClientHeartbeats', null, 5);
+        $generatorXml.property(res, disco, 'topHistorySize', null, 1000);
+        if ($generatorCommon.isDefinedAndNotEmpty(disco.listener))
+            $generatorXml.beanProperty(res, disco, 'listener', {className: disco.listener}, true);
+        if ($generatorCommon.isDefinedAndNotEmpty(disco.dataExchange))
+            $generatorXml.beanProperty(res, disco, 'dataExchange', {className: disco.dataExchange}, true);
+        if ($generatorCommon.isDefinedAndNotEmpty(disco.metricsProvider))
+            $generatorXml.beanProperty(res, disco, 'metricsProvider', {className: disco.metricsProvider}, true);
+        $generatorXml.property(res, disco, 'reconnectCount', null, 10);
+        $generatorXml.property(res, disco, 'statisticsPrintFrequency', null, 0);
+        $generatorXml.property(res, disco, 'ipFinderCleanFrequency', null, 60000);
+        if ($generatorCommon.isDefinedAndNotEmpty(disco.authenticator))
+            $generatorXml.beanProperty(res, disco, 'authenticator', {className: disco.authenticator}, true);
+        $generatorXml.property(res, disco, 'forceServerMode', null, false);
+        $generatorXml.property(res, disco, 'clientReconnectDisabled', null, false);
+
+        res.needEmptyLine = true;
+    }
+
+    return res;
+};
+
+// Generate events group.
+$generatorXml.clusterEvents = function(cluster, res) {
+    if (!res)
+        res = $generatorCommon.builder();
+
+    if (cluster.includeEventTypes && cluster.includeEventTypes.length > 0) {
+        res.emptyLineIfNeeded();
+
+        res.startBlock('<property name="includeEventTypes">');
+
+        const evtGrps = angular.element(document.getElementById('app')).injector().get('igniteEventGroups');
+
+        if (cluster.includeEventTypes.length === 1) {
+            const evtGrp = _.find(evtGrps, {value: cluster.includeEventTypes[0]});
+
+            if (evtGrp)
+                res.line('<util:constant static-field="' + evtGrp.class + '.' + evtGrp.value + '"/>');
+        }
+        else {
+            res.startBlock('<list>');
+
+            _.forEach(cluster.includeEventTypes, (item, ix) => {
+                ix > 0 && res.line();
+
+                const evtGrp = _.find(evtGrps, {value: item});
+
+                if (evtGrp) {
+                    res.line('<!-- EventType.' + item + ' -->');
+
+                    _.forEach(evtGrp.events, (event) => res.line('<util:constant static-field="' + evtGrp.class + '.' + event + '"/>'));
+                }
+            });
+
+            res.endBlock('</list>');
+        }
+
+        res.endBlock('</property>');
+
+        res.needEmptyLine = true;
+    }
+
+    return res;
+};
+
+// Generate failover group.
+$generatorXml.clusterFailover = function(cluster, res) {
+    if (!res)
+        res = $generatorCommon.builder();
+
+    if ($generatorCommon.isDefinedAndNotEmpty(cluster.failoverSpi) && _.findIndex(cluster.failoverSpi, function(spi) {
+        return $generatorCommon.isDefinedAndNotEmpty(spi.kind) && (spi.kind !== 'Custom' || $generatorCommon.isDefinedAndNotEmpty(_.get(spi, spi.kind + '.class')));
+    }) >= 0) {
+        res.startBlock('<property name="failoverSpi">');
+        res.startBlock('<list>');
+
+        _.forEach(cluster.failoverSpi, function(spi) {
+            if (spi.kind && (spi.kind !== 'Custom' || $generatorCommon.isDefinedAndNotEmpty(_.get(spi, spi.kind + '.class')))) {
+                const maxAttempts = _.get(spi, spi.kind + '.maximumFailoverAttempts');
+
+                if ((spi.kind === 'JobStealing' || spi.kind === 'Always') && $generatorCommon.isDefinedAndNotEmpty(maxAttempts) && maxAttempts !== 5) {
+                    res.startBlock('<bean class="' + $generatorCommon.failoverSpiClass(spi) + '">');
+
+                    $generatorXml.property(res, spi[spi.kind], 'maximumFailoverAttempts', null, 5);
+
+                    res.endBlock('</bean>');
+                }
+                else
+                    res.line('<bean class="' + $generatorCommon.failoverSpiClass(spi) + '"/>');
+
+                res.needEmptyLine = true;
+            }
+        });
+
+        res.needEmptyLine = true;
+
+        res.endBlock('</list>');
+        res.endBlock('</property>');
+    }
+
+    return res;
+};
+
+// Generate marshaller group.
+$generatorXml.clusterLogger = function(logger, res) {
+    if (!res)
+        res = $generatorCommon.builder();
+
+    if ($generatorCommon.loggerConfigured(logger)) {
+        res.startBlock('<property name="gridLogger">');
+
+        const log = logger[logger.kind];
+
+        switch (logger.kind) {
+            case 'Log4j2':
+                res.startBlock('<bean class="org.apache.ignite.logger.log4j2.Log4J2Logger">');
+                res.line('<constructor-arg value="' + $generatorXml.escape(log.path) + '"/>');
+                $generatorXml.property(res, log, 'level');
+                res.endBlock('</bean>');
+
+                break;
+
+            case 'Null':
+                res.line('<bean class="org.apache.ignite.logger.NullLogger"/>');
+
+                break;
+
+            case 'Java':
+                res.line('<bean class="org.apache.ignite.logger.java.JavaLogger"/>');
+
+                break;
+
+            case 'JCL':
+                res.line('<bean class="org.apache.ignite.logger.jcl.JclLogger"/>');
+
+                break;
+
+            case 'SLF4J':
+                res.line('<bean class="org.apache.ignite.logger.slf4j.Slf4jLogger"/>');
+
+                break;
+
+            case 'Log4j':
+                if (log.mode === 'Default' && !$generatorCommon.isDefinedAndNotEmpty(log.level))
+                    res.line('<bean class="org.apache.ignite.logger.log4j.Log4JLogger"/>');
+                else {
+                    res.startBlock('<bean class="org.apache.ignite.logger.log4j.Log4JLogger">');
+
+                    if (log.mode === 'Path')
+                        res.line('<constructor-arg value="' + $generatorXml.escape(log.path) + '"/>');
+
+                    $generatorXml.property(res, log, 'level');
+                    res.endBlock('</bean>');
+                }
+
+                break;
+
+            case 'Custom':
+                res.line('<bean class="' + log.class + '"/>');
+
+                break;
+
+            default:
+        }
+
+        res.endBlock('</property>');
+
+        res.needEmptyLine = true;
+    }
+
+    return res;
+};
+
+// Generate marshaller group.
+$generatorXml.clusterMarshaller = function(cluster, res) {
+    if (!res)
+        res = $generatorCommon.builder();
+
+    const marshaller = cluster.marshaller;
+
+    if (marshaller && marshaller.kind)
+        $generatorXml.beanProperty(res, marshaller[marshaller.kind], 'marshaller', $generatorCommon.MARSHALLERS[marshaller.kind], true);
+
+    res.softEmptyLine();
+
+    $generatorXml.property(res, cluster, 'marshalLocalJobs', null, false);
+    $generatorXml.property(res, cluster, 'marshallerCacheKeepAliveTime', null, 10000);
+    $generatorXml.property(res, cluster, 'marshallerCacheThreadPoolSize', 'marshallerCachePoolSize');
+
+    res.needEmptyLine = true;
+
+    return res;
+};
+
+// Generate metrics group.
+$generatorXml.clusterMetrics = function(cluster, res) {
+    if (!res)
+        res = $generatorCommon.builder();
+
+    $generatorXml.property(res, cluster, 'metricsExpireTime');
+    $generatorXml.property(res, cluster, 'metricsHistorySize', null, 10000);
+    $generatorXml.property(res, cluster, 'metricsLogFrequency', null, 60000);
+    $generatorXml.property(res, cluster, 'metricsUpdateFrequency', null, 2000);
+
+    res.needEmptyLine = true;
+
+    return res;
+};
+
+// Generate swap group.
+$generatorXml.clusterSwap = function(cluster, res) {
+    if (!res)
+        res = $generatorCommon.builder();
+
+    if (cluster.swapSpaceSpi && cluster.swapSpaceSpi.kind === 'FileSwapSpaceSpi') {
+        $generatorXml.beanProperty(res, cluster.swapSpaceSpi.FileSwapSpaceSpi, 'swapSpaceSpi',
+            $generatorCommon.SWAP_SPACE_SPI, true);
+
+        res.needEmptyLine = true;
+    }
+
+    return res;
+};
+
+// Generate time group.
+$generatorXml.clusterTime = function(cluster, res) {
+    if (!res)
+        res = $generatorCommon.builder();
+
+    $generatorXml.property(res, cluster, 'clockSyncSamples', null, 8);
+    $generatorXml.property(res, cluster, 'clockSyncFrequency', null, 120000);
+    $generatorXml.property(res, cluster, 'timeServerPortBase', null, 31100);
+    $generatorXml.property(res, cluster, 'timeServerPortRange', null, 100);
+
+    res.needEmptyLine = true;
+
+    return res;
+};
+
+// Generate thread pools group.
+$generatorXml.clusterPools = function(cluster, res) {
+    if (!res)
+        res = $generatorCommon.builder();
+
+    $generatorXml.property(res, cluster, 'publicThreadPoolSize');
+    $generatorXml.property(res, cluster, 'systemThreadPoolSize');
+    $generatorXml.property(res, cluster, 'managementThreadPoolSize');
+    $generatorXml.property(res, cluster, 'igfsThreadPoolSize');
+    $generatorXml.property(res, cluster, 'rebalanceThreadPoolSize');
+
+    res.needEmptyLine = true;
+
+    return res;
+};
+
+// Generate transactions group.
+$generatorXml.clusterTransactions = function(transactionConfiguration, res) {
+    if (!res)
+        res = $generatorCommon.builder();
+
+    $generatorXml.beanProperty(res, transactionConfiguration, 'transactionConfiguration', $generatorCommon.TRANSACTION_CONFIGURATION, false);
+
+    res.needEmptyLine = true;
+
+    return res;
+};
+
+// Generate user attributes group.
+$generatorXml.clusterUserAttributes = function(cluster, res) {
+    if (!res)
+        res = $generatorCommon.builder();
+
+    if ($generatorCommon.isDefinedAndNotEmpty(cluster.attributes)) {
+        res.startBlock('<property name="userAttributes">');
+        res.startBlock('<map>');
+
+        _.forEach(cluster.attributes, function(attr) {
+            $generatorXml.element(res, 'entry', 'key', attr.name, 'value', attr.value);
+        });
+
+        res.endBlock('</map>');
+        res.endBlock('</property>');
+    }
+
+    res.needEmptyLine = true;
+
+    return res;
+};
+
+/**
+ * XML generator for cluster's SSL configuration.
+ *
+ * @param cluster Cluster to get SSL configuration.
+ * @param res Optional configuration presentation builder object.
+ * @returns Configuration presentation builder object
+ */
+$generatorXml.clusterSsl = function(cluster, res) {
+    if (!res)
+        res = $generatorCommon.builder();
+
+    if (cluster.sslEnabled && !_.isNil(cluster.sslContextFactory)) {
+        let sslFactory;
+
+        if (_.isEmpty(cluster.sslContextFactory.keyStoreFilePath) && _.isEmpty(cluster.sslContextFactory.trustStoreFilePath))
+            sslFactory = cluster.sslContextFactory;
+        else {
+            sslFactory = _.clone(cluster.sslContextFactory);
+
+            sslFactory.keyStorePassword = _.isEmpty(cluster.sslContextFactory.keyStoreFilePath) ? null : '${ssl.key.storage.password}';
+            sslFactory.trustStorePassword = _.isEmpty(cluster.sslContextFactory.trustStoreFilePath) ? null : '${ssl.trust.storage.password}';
+        }
+
+        const propsDesc = $generatorCommon.isDefinedAndNotEmpty(cluster.sslContextFactory.trustManagers) ?
+            $generatorCommon.SSL_CONFIGURATION_TRUST_MANAGER_FACTORY :
+            $generatorCommon.SSL_CONFIGURATION_TRUST_FILE_FACTORY;
+
+        $generatorXml.beanProperty(res, sslFactory, 'sslContextFactory', propsDesc, true);
+
+        res.needEmptyLine = true;
+    }
+
+    return res;
+};
+
+// Generate cache general group.
+$generatorXml.cacheGeneral = function(cache, res) {
+    if (!res)
+        res = $generatorCommon.builder();
+
+    $generatorXml.property(res, cache, 'name');
+
+    $generatorXml.property(res, cache, 'cacheMode');
+    $generatorXml.property(res, cache, 'atomicityMode');
+
+    if (cache.cacheMode === 'PARTITIONED' && $generatorXml.property(res, cache, 'backups'))
+        $generatorXml.property(res, cache, 'readFromBackup');
+
+    $generatorXml.property(res, cache, 'copyOnRead');
+
+    if (cache.cacheMode === 'PARTITIONED' && cache.atomicityMode === 'TRANSACTIONAL')
+        $generatorXml.property(res, cache, 'invalidate');
+
+    res.needEmptyLine = true;
+
+    return res;
+};
+
+// Generate cache memory group.
+$generatorXml.cacheMemory = function(cache, res) {
+    if (!res)
+        res = $generatorCommon.builder();
+
+    $generatorXml.property(res, cache, 'memoryMode', null, 'ONHEAP_TIERED');
+
+    if (cache.memoryMode !== 'OFFHEAP_VALUES')
+        $generatorXml.property(res, cache, 'offHeapMaxMemory', null, -1);
+
+    res.softEmptyLine();
+
+    $generatorXml.evictionPolicy(res, cache.evictionPolicy, 'evictionPolicy');
+
+    res.softEmptyLine();
+
+    $generatorXml.property(res, cache, 'startSize', null, 1500000);
+    $generatorXml.property(res, cache, 'swapEnabled', null, false);
+
+    res.needEmptyLine = true;
+
+    return res;
+};
+
+// Generate cache query & indexing group.
+$generatorXml.cacheQuery = function(cache, domains, res) {
+    if (!res)
+        res = $generatorCommon.builder();
+
+    $generatorXml.property(res, cache, 'sqlSchema');
+    $generatorXml.property(res, cache, 'sqlOnheapRowCacheSize', null, 10240);
+    $generatorXml.property(res, cache, 'longQueryWarningTimeout', null, 3000);
+
+    const indexedTypes = _.filter(domains, (domain) => domain.queryMetadata === 'Annotations');
+
+    if (indexedTypes.length > 0) {
+        res.softEmptyLine();
+
+        res.startBlock('<property name="indexedTypes">');
+        res.startBlock('<list>');
+
+        _.forEach(indexedTypes, function(domain) {
+            res.line('<value>' + $generatorCommon.JavaTypes.fullClassName(domain.keyType) + '</value>');
+            res.line('<value>' + $generatorCommon.JavaTypes.fullClassName(domain.valueType) + '</value>');
+        });
+
+        res.endBlock('</list>');
+        res.endBlock('</property>');
+    }
+
+    res.softEmptyLine();
+
+    $generatorXml.listProperty(res, cache, 'sqlFunctionClasses');
+
+    res.softEmptyLine();
+
+    $generatorXml.property(res, cache, 'snapshotableIndex', null, false);
+    $generatorXml.property(res, cache, 'sqlEscapeAll', null, false);
+
+    res.needEmptyLine = true;
+
+    return res;
+};
+
+// Generate cache store group.
+$generatorXml.cacheStore = function(cache, domains, res) {
+    if (!res)
+        res = $generatorCommon.builder();
+
+    if (cache.cacheStoreFactory && cache.cacheStoreFactory.kind) {
+        const factoryKind = cache.cacheStoreFactory.kind;
+
+        const storeFactory = cache.cacheStoreFactory[factoryKind];
+
+        if (storeFactory) {
+            if (factoryKind === 'CacheJdbcPojoStoreFactory') {
+                res.startBlock('<property name="cacheStoreFactory">');
+                res.startBlock('<bean class="org.apache.ignite.cache.store.jdbc.CacheJdbcPojoStoreFactory">');
+
+                $generatorXml.property(res, storeFactory, 'dataSourceBean');
+
+                res.startBlock('<property name="dialect">');
+                res.line('<bean class="' + $generatorCommon.jdbcDialectClassName(storeFactory.dialect) + '"/>');
+                res.endBlock('</property>');
+
+                const domainConfigs = _.filter(domains, function(domain) {
+                    return $generatorCommon.isDefinedAndNotEmpty(domain.databaseTable);
+                });
+
+                if ($generatorCommon.isDefinedAndNotEmpty(domainConfigs)) {
+                    res.startBlock('<property name="types">');
+                    res.startBlock('<list>');
+
+                    _.forEach(domainConfigs, function(domain) {
+                        res.startBlock('<bean class="org.apache.ignite.cache.store.jdbc.JdbcType">');
+
+                        $generatorXml.property(res, cache, 'name', 'cacheName');
+
+                        $generatorXml.classNameProperty(res, domain, 'keyType');
+                        $generatorXml.property(res, domain, 'valueType');
+
+                        $generatorXml.domainStore(domain, res);
+
+                        res.endBlock('</bean>');
+                    });
+
+                    res.endBlock('</list>');
+                    res.endBlock('</property>');
+                }
+
+                res.endBlock('</bean>');
+                res.endBlock('</property>');
+            }
+            else if (factoryKind === 'CacheJdbcBlobStoreFactory') {
+                res.startBlock('<property name="cacheStoreFactory">');
+                res.startBlock('<bean class="org.apache.ignite.cache.store.jdbc.CacheJdbcBlobStoreFactory">');
+
+                if (storeFactory.connectVia === 'DataSource')
+                    $generatorXml.property(res, storeFactory, 'dataSourceBean');
+                else {
+                    $generatorXml.property(res, storeFactory, 'connectionUrl');
+                    $generatorXml.property(res, storeFactory, 'user');
+                    res.line('<property name="password" value="${ds.' + storeFactory.user + '.password}"/>');
+                }
+
+                $generatorXml.property(res, storeFactory, 'initSchema');
+                $generatorXml.property(res, storeFactory, 'createTableQuery');
+                $generatorXml.property(res, storeFactory, 'loadQuery');
+                $generatorXml.property(res, storeFactory, 'insertQuery');
+                $generatorXml.property(res, storeFactory, 'updateQuery');
+                $generatorXml.property(res, storeFactory, 'deleteQuery');
+
+                res.endBlock('</bean>');
+                res.endBlock('</property>');
+            }
+            else
+                $generatorXml.beanProperty(res, storeFactory, 'cacheStoreFactory', $generatorCommon.STORE_FACTORIES[factoryKind], true);
+
+            if (storeFactory.dataSourceBean && (storeFactory.connectVia ? (storeFactory.connectVia === 'DataSource' ? storeFactory.dialect : null) : storeFactory.dialect)) {
+                if (_.findIndex(res.datasources, (ds) => ds.dataSourceBean === storeFactory.dataSourceBean) < 0) {
+                    res.datasources.push({
+                        dataSourceBean: storeFactory.dataSourceBean,
+                        dialect: storeFactory.dialect
+                    });
+                }
+            }
+        }
+    }
+
+    res.softEmptyLine();
+
+    $generatorXml.property(res, cache, 'storeKeepBinary', null, false);
+    $generatorXml.property(res, cache, 'loadPreviousValue', null, false);
+    $generatorXml.property(res, cache, 'readThrough', null, false);
+    $generatorXml.property(res, cache, 'writeThrough', null, false);
+
+    res.softEmptyLine();
+
+    if (cache.writeBehindEnabled) {
+        $generatorXml.property(res, cache, 'writeBehindEnabled', null, false);
+        $generatorXml.property(res, cache, 'writeBehindBatchSize', null, 512);
+        $generatorXml.property(res, cache, 'writeBehindFlushSize', null, 10240);
+        $generatorXml.property(res, cache, 'writeBehindFlushFrequency', null, 5000);
+        $generatorXml.property(res, cache, 'writeBehindFlushThreadCount', null, 1);
+    }
+
+    res.needEmptyLine = true;
+
+    return res;
+};
+
+// Generate cache node filter group.
+$generatorXml.cacheNodeFilter = function(cache, igfss, res) {
+    if (!res)
+        res = $generatorCommon.builder();
+
+    const kind = _.get(cache, 'nodeFilter.kind');
+
+    if (_.isNil(kind) || _.isNil(cache.nodeFilter[kind]))
+        return res;
+
+    switch (kind) {
+        case 'IGFS':
+            const foundIgfs = _.find(igfss, (igfs) => igfs._id === cache.nodeFilter.IGFS.igfs);
+
+            if (foundIgfs) {
+                res.startBlock('<property name="nodeFilter">');
+                res.startBlock('<bean class="org.apache.ignite.internal.processors.igfs.IgfsNodePredicate">');
+                res.line('<constructor-arg value="' + foundIgfs.name + '"/>');
+                res.endBlock('</bean>');
+                res.endBlock('</property>');
+            }
+
+            break;
+
+        case 'OnNodes':
+            const nodes = cache.nodeFilter.OnNodes.nodeIds;
+
+            if ($generatorCommon.isDefinedAndNotEmpty(nodes)) {
+                res.startBlock('<property name="nodeFilter">');
+                res.startBlock('<bean class="org.apache.ignite.internal.util.lang.GridNodePredicate">');
+                res.startBlock('<constructor-arg>');
+                res.startBlock('<list>');
+
+                _.forEach(nodes, (nodeId) => {
+                    res.startBlock('<bean class="java.util.UUID" factory-method="fromString">');
+                    res.line('<constructor-arg value="' + nodeId + '"/>');
+                    res.endBlock('</bean>');
+                });
+
+                res.endBlock('</list>');
+                res.endBlock('</constructor-arg>');
+                res.endBlock('</bean>');
+                res.endBlock('</property>');
+            }
+
+            break;
+
+        case 'Custom':
+            res.startBlock('<property name="nodeFilter">');
+            res.line('<bean class="' + cache.nodeFilter.Custom.className + '"/>');
+            res.endBlock('</property>');
+
+            break;
+
+        default: break;
+    }
+
+    res.needEmptyLine = true;
+
+    return res;
+};
+
+// Generate cache concurrency group.
+$generatorXml.cacheConcurrency = function(cache, res) {
+    if (!res)
+        res = $generatorCommon.builder();
+
+    $generatorXml.property(res, cache, 'maxConcurrentAsyncOperations', null, 500);
+    $generatorXml.property(res, cache, 'defaultLockTimeout', null, 0);
+    $generatorXml.property(res, cache, 'atomicWriteOrderMode');
+    $generatorXml.property(res, cache, 'writeSynchronizationMode', null, 'PRIMARY_SYNC');
+
+    res.needEmptyLine = true;
+
+    return res;
+};
+
+// Generate cache rebalance group.
+$generatorXml.cacheRebalance = function(cache, res) {
+    if (!res)
+        res = $generatorCommon.builder();
+
+    if (cache.cacheMode !== 'LOCAL') {
+        $generatorXml.property(res, cache, 'rebalanceMode', null, 'ASYNC');
+        $generatorXml.property(res, cache, 'rebalanceThreadPoolSize', null, 1);
+        $generatorXml.property(res, cache, 'rebalanceBatchSize', null, 524288);
+        $generatorXml.property(res, cache, 'rebalanceBatchesPrefetchCount', null, 2);
+        $generatorXml.property(res, cache, 'rebalanceOrder', null, 0);
+        $generatorXml.property(res, cache, 'rebalanceDelay', null, 0);
+        $generatorXml.property(res, cache, 'rebalanceTimeout', null, 10000);
+        $generatorXml.property(res, cache, 'rebalanceThrottle', null, 0);
+    }
+
+    res.softEmptyLine();
+
+    if (cache.igfsAffinnityGroupSize) {
+        res.startBlock('<property name="affinityMapper">');
+        res.startBlock('<bean class="org.apache.ignite.igfs.IgfsGroupDataBlocksKeyMapper">');
+        $generatorXml.constructorArg(res, -1, cache, 'igfsAffinnityGroupSize');
+        res.endBlock('</bean>');
+        res.endBlock('</property>');
+    }
+
+    return res;
+};
+
+// Generate cache server near cache group.
+$generatorXml.cacheServerNearCache = function(cache, res) {
+    if (!res)
+        res = $generatorCommon.builder();
+
+    if (cache.cacheMode === 'PARTITIONED' && cache.nearCacheEnabled) {
+        res.emptyLineIfNeeded();
+
+        res.startBlock('<property name="nearConfiguration">');
+        res.startBlock('<bean class="org.apache.ignite.configuration.NearCacheConfiguration">');
+
+        if (cache.nearConfiguration) {
+            if (cache.nearConfiguration.nearStartSize)
+                $generatorXml.property(res, cache.nearConfiguration, 'nearStartSize', null, 375000);
+
+            $generatorXml.evictionPolicy(res, cache.nearConfiguration.nearEvictionPolicy, 'nearEvictionPolicy');
+        }
+
+        res.endBlock('</bean>');
+        res.endBlock('</property>');
+    }
+
+    res.needEmptyLine = true;
+
+    return res;
+};
+
+// Generate cache statistics group.
+$generatorXml.cacheStatistics = function(cache, res) {
+    if (!res)
+        res = $generatorCommon.builder();
+
+    $generatorXml.property(res, cache, 'statisticsEnabled', null, false);
+    $generatorXml.property(res, cache, 'managementEnabled', null, false);
+
+    res.needEmptyLine = true;
+
+    return res;
+};
+
+// Generate domain model query fields.
+$generatorXml.domainModelQueryFields = function(res, domain) {
+    const fields = domain.fields;
+
+    if (fields && fields.length > 0) {
+        res.emptyLineIfNeeded();
+
+        res.startBlock('<property name="fields">');
+        res.startBlock('<map>');
+
+        _.forEach(fields, function(field) {
+            $generatorXml.element(res, 'entry', 'key', field.name, 'value', $generatorCommon.JavaTypes.fullClassName(field.className));
+        });
+
+        res.endBlock('</map>');
+        res.endBlock('</property>');
+
+        res.needEmptyLine = true;
+    }
+};
+
+// Generate domain model query fields.
+$generatorXml.domainModelQueryAliases = function(res, domain) {
+    const aliases = domain.aliases;
+
+    if (aliases && aliases.length > 0) {
+        res.emptyLineIfNeeded();
+
+        res.startBlock('<property name="aliases">');
+        res.startBlock('<map>');
+
+        _.forEach(aliases, function(alias) {
+            $generatorXml.element(res, 'entry', 'key', alias.field, 'value', alias.alias);
+        });
+
+        res.endBlock('</map>');
+        res.endBlock('</property>');
+
+        res.needEmptyLine = true;
+    }
+};
+
+// Generate domain model indexes.
+$generatorXml.domainModelQueryIndexes = function(res, domain) {
+    const indexes = domain.indexes;
+
+    if (indexes && indexes.length > 0) {
+        res.emptyLineIfNeeded();
+
+        res.startBlock('<property name="indexes">');
+        res.startBlock('<list>');
+
+        _.forEach(indexes, function(index) {
+            res.startBlock('<bean class="org.apache.ignite.cache.QueryIndex">');
+
+            $generatorXml.property(res, index, 'name');
+            $generatorXml.property(res, index, 'indexType');
+
+            const fields = index.fields;
+
+            if (fields && fields.length > 0) {
+                res.startBlock('<property name="fields">');
+                res.startBlock('<map>');
+
+                _.forEach(fields, function(field) {
+                    $generatorXml.element(res, 'entry', 'key', field.name, 'value', field.direction);
+                });
+
+                res.endBlock('</map>');
+                res.endBlock('</property>');
+            }
+
+            res.endBlock('</bean>');
+        });
+
+        res.endBlock('</list>');
+        res.endBlock('</property>');
+
+        res.needEmptyLine = true;
+    }
+};
+
+// Generate domain model db fields.
+$generatorXml.domainModelDatabaseFields = function(res, domain, fieldProp) {
+    const fields = domain[fieldProp];
+
+    if (fields && fields.length > 0) {
+        res.emptyLineIfNeeded();
+
+        res.startBlock('<property name="' + fieldProp + '">');
+
+        res.startBlock('<list>');
+
+        _.forEach(fields, function(field) {
+            res.startBlock('<bean class="org.apache.ignite.cache.store.jdbc.JdbcTypeField">');
+
+            $generatorXml.property(res, field, 'databaseFieldName');
+
+            res.startBlock('<property name="databaseFieldType">');
+            res.line('<util:constant static-field="java.sql.Types.' + field.databaseFieldType + '"/>');
+            res.endBlock('</property>');
+
+            $generatorXml.property(res, field, 'javaFieldName');
+
+            $generatorXml.classNameProperty(res, field, 'javaFieldType');
+
+            res.endBlock('</bean>');
+        });
+
+        res.endBlock('</list>');
+        res.endBlock('</property>');
+
+        res.needEmptyLine = true;
+    }
+};
+
+// Generate domain model general group.
+$generatorXml.domainModelGeneral = function(domain, res) {
+    if (!res)
+        res = $generatorCommon.builder();
+
+    switch ($generatorCommon.domainQueryMetadata(domain)) {
+        case 'Annotations':
+            if ($generatorCommon.isDefinedAndNotEmpty(domain.keyType) || $generatorCommon.isDefinedAndNotEmpty(domain.valueType)) {
+                res.startBlock('<property name="indexedTypes">');
+                res.startBlock('<list>');
+
+                if ($generatorCommon.isDefinedAndNotEmpty(domain.keyType))
+                    res.line('<value>' + $generatorCommon.JavaTypes.fullClassName(domain.keyType) + '</value>');
+                else
+                    res.line('<value>???</value>');
+
+                if ($generatorCommon.isDefinedAndNotEmpty(domain.valueType))
+                    res.line('<value>' + $generatorCommon.JavaTypes.fullClassName(domain.valueType) + '</value>');
+                else
+                    res.line('<value>>???</value>');
+
+                res.endBlock('</list>');
+                res.endBlock('</property>');
+            }
+
+            break;
+
+        case 'Configuration':
+            $generatorXml.classNameProperty(res, domain, 'keyType');
+            $generatorXml.property(res, domain, 'valueType');
+
+            break;
+
+        default:
+    }
+
+    res.needEmptyLine = true;
+
+    return res;
+};
+
+// Generate domain model for query group.
+$generatorXml.domainModelQuery = function(domain, res) {
+    if (!res)
+        res = $generatorCommon.builder();
+
+    if ($generatorCommon.domainQueryMetadata(domain) === 'Configuration') {
+        $generatorXml.domainModelQueryFields(res, domain);
+        $generatorXml.domainModelQueryAliases(res, domain);
+        $generatorXml.domainModelQueryIndexes(res, domain);
+
+        res.needEmptyLine = true;
+    }
+
+    return res;
+};
+
+// Generate domain model for store group.
+$generatorXml.domainStore = function(domain, res) {
+    if (!res)
+        res = $generatorCommon.builder();
+
+    $generatorXml.property(res, domain, 'databaseSchema');
+    $generatorXml.property(res, domain, 'databaseTable');
+
+    res.softEmptyLine();
+
+    $generatorXml.domainModelDatabaseFields(res, domain, 'keyFields');
+    $generatorXml.domainModelDatabaseFields(res, domain, 'valueFields');
+
+    res.needEmptyLine = true;
+
+    return res;
+};
+
+$generatorXml.cacheQueryMetadata = function(domain, res) {
+    if (!res)
+        res = $generatorCommon.builder();
+
+    res.startBlock('<bean class="org.apache.ignite.cache.QueryEntity">');
+
+    $generatorXml.classNameProperty(res, domain, 'keyType');
+    $generatorXml.property(res, domain, 'valueType');
+
+    $generatorXml.domainModelQuery(domain, res);
+
+    res.endBlock('</bean>');
+
+    res.needEmptyLine = true;
+
+    return res;
+};
+
+// Generate domain models configs.
+$generatorXml.cacheDomains = function(domains, res) {
+    if (!res)
+        res = $generatorCommon.builder();
+
+    const domainConfigs = _.filter(domains, function(domain) {
+        return $generatorCommon.domainQueryMetadata(domain) === 'Configuration' &&
+            $generatorCommon.isDefinedAndNotEmpty(domain.fields);
+    });
+
+    if ($generatorCommon.isDefinedAndNotEmpty(domainConfigs)) {
+        res.emptyLineIfNeeded();
+
+        res.startBlock('<property name="queryEntities">');
+        res.startBlock('<list>');
+
+        _.forEach(domainConfigs, function(domain) {
+            $generatorXml.cacheQueryMetadata(domain, res);
+        });
+
+        res.endBlock('</list>');
+        res.endBlock('</property>');
+    }
+
+    return res;
+};
+
+// Generate cache configs.
+$generatorXml.cache = function(cache, res) {
+    if (!res)
+        res = $generatorCommon.builder();
+
+    res.startBlock('<bean class="org.apache.ignite.configuration.CacheConfiguration">');
+
+    $generatorXml.cacheConfiguration(cache, res);
+
+    res.endBlock('</bean>');
+
+    return res;
+};
+
+// Generate cache configs.
+$generatorXml.cacheConfiguration = function(cache, res) {
+    if (!res)
+        res = $generatorCommon.builder();
+
+    $generatorXml.cacheGeneral(cache, res);
+    $generatorXml.cacheMemory(cache, res);
+    $generatorXml.cacheQuery(cache, cache.domains, res);
+    $generatorXml.cacheStore(cache, cache.domains, res);
+
+    const igfs = _.get(cache, 'nodeFilter.IGFS.instance');
+
+    $generatorXml.cacheNodeFilter(cache, igfs ? [igfs] : [], res);
+    $generatorXml.cacheConcurrency(cache, res);
+    $generatorXml.cacheRebalance(cache, res);
+    $generatorXml.cacheServerNearCache(cache, res);
+    $generatorXml.cacheStatistics(cache, res);
+    $generatorXml.cacheDomains(cache.domains, res);
+
+    return res;
+};
+
+// Generate caches configs.
+$generatorXml.clusterCaches = function(caches, igfss, isSrvCfg, res) {
+    if (!res)
+        res = $generatorCommon.builder();
+
+    if ($generatorCommon.isDefinedAndNotEmpty(caches) || (isSrvCfg && $generatorCommon.isDefinedAndNotEmpty(igfss))) {
+        res.emptyLineIfNeeded();
+
+        res.startBlock('<property name="cacheConfiguration">');
+        res.startBlock('<list>');
+
+        _.forEach(caches, function(cache) {
+            $generatorXml.cache(cache, res);
+
+            res.needEmptyLine = true;
+        });
+
+        if (isSrvCfg) {
+            _.forEach(igfss, (igfs) => {
+                $generatorXml.cache($generatorCommon.igfsDataCache(igfs), res);
+
+                res.needEmptyLine = true;
+
+                $generatorXml.cache($generatorCommon.igfsMetaCache(igfs), res);
+
+                res.needEmptyLine = true;
+            });
+        }
+
+        res.endBlock('</list>');
+        res.endBlock('</property>');
+
+        res.needEmptyLine = true;
+    }
+
+    return res;
+};
+
+// Generate IGFSs configs.
+$generatorXml.igfss = function(igfss, res) {
+    if (!res)
+        res = $generatorCommon.builder();
+
+    if ($generatorCommon.isDefinedAndNotEmpty(igfss)) {
+        res.emptyLineIfNeeded();
+
+        res.startBlock('<property name="fileSystemConfiguration">');
+        res.startBlock('<list>');
+
+        _.forEach(igfss, function(igfs) {
+            res.startBlock('<bean class="org.apache.ignite.configuration.FileSystemConfiguration">');
+
+            $generatorXml.igfsGeneral(igfs, res);
+            $generatorXml.igfsIPC(igfs, res);
+            $generatorXml.igfsFragmentizer(igfs, res);
+            $generatorXml.igfsDualMode(igfs, res);
+            $generatorXml.igfsSecondFS(igfs, res);
+            $generatorXml.igfsMisc(igfs, res);
+
+            res.endBlock('</bean>');
+
+            res.needEmptyLine = true;
+        });
+
+        res.endBlock('</list>');
+        res.endBlock('</property>');
+
+        res.needEmptyLine = true;
+    }
+
+    return res;
+};
+
+// Generate IGFS IPC configuration.
+$generatorXml.igfsIPC = function(igfs, res) {
+    if (!res)
+        res = $generatorCommon.builder();
+
+    if (igfs.ipcEndpointEnabled) {
+        $generatorXml.beanProperty(res, igfs.ipcEndpointConfiguration, 'ipcEndpointConfiguration', $generatorCommon.IGFS_IPC_CONFIGURATION, true);
+
+        res.needEmptyLine = true;
+    }
+
+    return res;
+};
+
+// Generate IGFS fragmentizer configuration.
+$generatorXml.igfsFragmentizer = function(igfs, res) {
+    if (!res)
+        res = $generatorCommon.builder();
+
+    if (igfs.fragmentizerEnabled) {
+        $generatorXml.property(res, igfs, 'fragmentizerConcurrentFiles', null, 0);
+        $generatorXml.property(res, igfs, 'fragmentizerThrottlingBlockLength', null, 16777216);
+        $generatorXml.property(res, igfs, 'fragmentizerThrottlingDelay', null, 200);
+
+        res.needEmptyLine = true;
+    }
+    else
+        $generatorXml.property(res, igfs, 'fragmentizerEnabled');
+
+    return res;
+};
+
+// Generate IGFS dual mode configuration.
+$generatorXml.igfsDualMode = function(igfs, res) {
+    if (!res)
+        res = $generatorCommon.builder();
+
+    $generatorXml.property(res, igfs, 'dualModeMaxPendingPutsSize', null, 0);
+
+    if ($generatorCommon.isDefinedAndNotEmpty(igfs.dualModePutExecutorService)) {
+        res.startBlock('<property name="dualModePutExecutorService">');
+        res.line('<bean class="' + igfs.dualModePutExecutorService + '"/>');
+        res.endBlock('</property>');
+    }
+
+    $generatorXml.property(res, igfs, 'dualModePutExecutorServiceShutdown', null, false);
+
+    res.needEmptyLine = true;
+
+    return res;
+};
+
+$generatorXml.igfsSecondFS = function(igfs, res) {
+    if (!res)
+        res = $generatorCommon.builder();
+
+    if (igfs.secondaryFileSystemEnabled) {
+        const secondFs = igfs.secondaryFileSystem || {};
+
+        res.startBlock('<property name="secondaryFileSystem">');
+
+        res.startBlock('<bean class="org.apache.ignite.hadoop.fs.IgniteHadoopIgfsSecondaryFileSystem">');
+
+        const nameDefined = $generatorCommon.isDefinedAndNotEmpty(secondFs.userName);
+        const cfgDefined = $generatorCommon.isDefinedAndNotEmpty(secondFs.cfgPath);
+
+        $generatorXml.constructorArg(res, 0, secondFs, 'uri');
+
+        if (cfgDefined || nameDefined)
+            $generatorXml.constructorArg(res, 1, secondFs, 'cfgPath');
+
+        $generatorXml.constructorArg(res, 2, secondFs, 'userName', null, true);
+
+        res.endBlock('</bean>');
+        res.endBlock('</property>');
+
+        res.needEmptyLine = true;
+    }
+
+    return res;
+};
+
+// Generate IGFS general configuration.
+$generatorXml.igfsGeneral = function(igfs, res) {
+    if (!res)
+        res = $generatorCommon.builder();
+
+    if ($generatorCommon.isDefinedAndNotEmpty(igfs.name)) {
+        igfs.dataCacheName = $generatorCommon.igfsDataCache(igfs).name;
+        igfs.metaCacheName = $generatorCommon.igfsMetaCache(igfs).name;
+
+        $generatorXml.property(res, igfs, 'name');
+        $generatorXml.property(res, igfs, 'dataCacheName');
+        $generatorXml.property(res, igfs, 'metaCacheName');
+        $generatorXml.property(res, igfs, 'defaultMode', null, 'DUAL_ASYNC');
+
+        res.needEmptyLine = true;
+    }
+
+    return res;
+};
+
+// Generate IGFS misc configuration.
+$generatorXml.igfsMisc = function(igfs, res) {
+    if (!res)
+        res = $generatorCommon.builder();
+
+    $generatorXml.property(res, igfs, 'blockSize', null, 65536);
+    $generatorXml.property(res, igfs, 'streamBufferSize', null, 65536);
+    $generatorXml.property(res, igfs, 'maxSpaceSize', null, 0);
+    $generatorXml.property(res, igfs, 'maximumTaskRangeLength', null, 0);
+    $generatorXml.property(res, igfs, 'managementPort', null, 11400);
+    $generatorXml.property(res, igfs, 'perNodeBatchSize', null, 100);
+    $generatorXml.property(res, igfs, 'perNodeParallelBatchCount', null, 8);
+    $generatorXml.property(res, igfs, 'prefetchBlocks', null, 0);
+    $generatorXml.property(res, igfs, 'sequentialReadsBeforePrefetch', null, 0);
+    $generatorXml.property(res, igfs, 'trashPurgeTimeout', null, 1000);
+    $generatorXml.property(res, igfs, 'colocateMetadata', null, true);
+    $generatorXml.property(res, igfs, 'relaxedConsistency', null, true);
+
+    res.softEmptyLine();
+
+    if (igfs.pathModes && igfs.pathModes.length > 0) {
+        res.startBlock('<property name="pathModes">');
+        res.startBlock('<map>');
+
+        _.forEach(igfs.pathModes, function(pair) {
+            res.line('<entry key="' + pair.path + '" value="' + pair.mode + '"/>');
+        });
+
+        res.endBlock('</map>');
+        res.endBlock('</property>');
+    }
+
+    return res;
+};
+
+// Generate DataSource beans.
+$generatorXml.generateDataSources = function(datasources, res) {
+    if (!res)
+        res = $generatorCommon.builder();
+
+    if (datasources.length > 0) {
+        res.line('<!-- Data source beans will be initialized from external properties file. -->');
+
+        _.forEach(datasources, (datasource) => $generatorXml.generateDataSource(datasource, res));
+
+        res.needEmptyLine = true;
+
+        res.emptyLineIfNeeded();
+    }
+
+    return res;
+};
+
+$generatorXml.generateDataSource = function(datasource, res) {
+    const beanId = datasource.dataSourceBean;
+
+    res.startBlock('<bean id="' + beanId + '" class="' + $generatorCommon.DATA_SOURCES[datasource.dialect] + '">');
+
+    switch (datasource.dialect) {
+        case 'Generic':
+            res.line('<property name="jdbcUrl" value="${' + beanId + '.jdbc.url}"/>');
+
+            break;
+
+        case 'DB2':
+            res.line('<property name="serverName" value="${' + beanId + '.jdbc.server_name}"/>');
+            res.line('<property name="portNumber" value="${' + beanId + '.jdbc.port_number}"/>');
+            res.line('<property name="databaseName" value="${' + beanId + '.jdbc.database_name}"/>');
+            res.line('<property name="driverType" value="${' + beanId + '.jdbc.driver_type}"/>');
+
+            break;
+
+        case 'PostgreSQL':
+            res.line('<property name="url" value="${' + beanId + '.jdbc.url}"/>');
+
+            break;
+
+        default:
+            res.line('<property name="URL" value="${' + beanId + '.jdbc.url}"/>');
+    }
+
+    res.line('<property name="user" value="${' + beanId + '.jdbc.username}"/>');
+    res.line('<property name="password" value="${' + beanId + '.jdbc.password}"/>');
+
+    res.endBlock('</bean>');
+
+    res.needEmptyLine = true;
+
+    res.emptyLineIfNeeded();
+};
+
+$generatorXml.clusterConfiguration = function(cluster, clientNearCfg, res) {
+    const isSrvCfg = _.isNil(clientNearCfg);
+
+    if (!isSrvCfg) {
+        res.line('<property name="clientMode" value="true"/>');
+
+        res.needEmptyLine = true;
+    }
+
+    $generatorXml.clusterGeneral(cluster, res);
+
+    $generatorXml.clusterAtomics(cluster.atomicConfiguration, res);
+
+    $generatorXml.clusterBinary(cluster.binaryConfiguration, res);
+
+    $generatorXml.clusterCacheKeyConfiguration(cluster.cacheKeyConfiguration, res);
+
+    $generatorXml.clusterCollision(cluster.collision, res);
+
+    $generatorXml.clusterCommunication(cluster, res);
+
+    $generatorXml.clusterConnector(cluster.connector, res);
+
+    $generatorXml.clusterDeployment(cluster, res);
+
+    $generatorXml.clusterEvents(cluster, res);
+
+    $generatorXml.clusterFailover(cluster, res);
+
+    $generatorXml.clusterLogger(cluster.logger, res);
+
+    $generatorXml.clusterMarshaller(cluster, res);
+
+    $generatorXml.clusterMetrics(cluster, res);
+
+    $generatorXml.clusterSwap(cluster, res);
+
+    $generatorXml.clusterTime(cluster, res);
+
+    $generatorXml.clusterPools(cluster, res);
+
+    $generatorXml.clusterTransactions(cluster.transactionConfiguration, res);
+
+    $generatorXml.clusterCaches(cluster.caches, cluster.igfss, isSrvCfg, res);
+
+    $generatorXml.clusterSsl(cluster, res);
+
+    if (isSrvCfg)
+        $generatorXml.igfss(cluster.igfss, res);
+
+    $generatorXml.clusterUserAttributes(cluster, res);
+
+    return res;
+};
+
+$generatorXml.cluster = function(cluster, clientNearCfg) {
+    if (cluster) {
+        const res = $generatorCommon.builder(1);
+
+        if (clientNearCfg) {
+            res.startBlock('<bean id="nearCacheBean" class="org.apache.ignite.configuration.NearCacheConfiguration">');
+
+            if (clientNearCfg.nearStartSize)
+                $generatorXml.property(res, clientNearCfg, 'nearStartSize');
+
+            if (clientNearCfg.nearEvictionPolicy && clientNearCfg.nearEvictionPolicy.kind)
+                $generatorXml.evictionPolicy(res, clientNearCfg.nearEvictionPolicy, 'nearEvictionPolicy');
+
+            res.endBlock('</bean>');
+
+            res.needEmptyLine = true;
+
+            res.emptyLineIfNeeded();
+        }
+
+        // Generate Ignite Configuration.
+        res.startBlock('<bean class="org.apache.ignite.configuration.IgniteConfiguration">');
+
+        $generatorXml.clusterConfiguration(cluster, clientNearCfg, res);
+
+        res.endBlock('</bean>');
+
+        // Build final XML:
+        // 1. Add header.
+        let xml = '<?xml version="1.0" encoding="UTF-8"?>\n\n';
+
+        xml += '<!-- ' + $generatorCommon.mainComment() + ' -->\n\n';
+        xml += '<beans xmlns="http://www.springframework.org/schema/beans"\n';
+        xml += '       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"\n';
+        xml += '       xmlns:util="http://www.springframework.org/schema/util"\n';
+        xml += '       xsi:schemaLocation="http://www.springframework.org/schema/beans\n';
+        xml += '                           http://www.springframework.org/schema/beans/spring-beans.xsd\n';
+        xml += '                           http://www.springframework.org/schema/util\n';
+        xml += '                           http://www.springframework.org/schema/util/spring-util.xsd">\n';
+
+        // 2. Add external property file
+        if ($generatorCommon.secretPropertiesNeeded(cluster)) {
+            xml += '    <!-- Load external properties file. -->\n';
+            xml += '    <bean id="placeholderConfig" class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">\n';
+            xml += '        <property name="location" value="classpath:secret.properties"/>\n';
+            xml += '    </bean>\n\n';
+        }
+
+        // 3. Add data sources.
+        xml += $generatorXml.generateDataSources(res.datasources, $generatorCommon.builder(1)).asString();
+
+        // 3. Add main content.
+        xml += res.asString();
+
+        // 4. Add footer.
+        xml += '\n</beans>';
+
+        return xml;
+    }
+
+    return '';
+};
+
+export default $generatorXml;


[35/52] ignite git commit: Web Console beta-3.

Posted by ak...@apache.org.
http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/frontend/app/modules/states/configuration/caches/node-filter.jade
----------------------------------------------------------------------
diff --git a/modules/web-console/frontend/app/modules/states/configuration/caches/node-filter.jade b/modules/web-console/frontend/app/modules/states/configuration/caches/node-filter.jade
new file mode 100644
index 0000000..ee28c87
--- /dev/null
+++ b/modules/web-console/frontend/app/modules/states/configuration/caches/node-filter.jade
@@ -0,0 +1,108 @@
+//-
+    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.jade
+
+-var form = 'nodeFilter'
+-var model = 'backupItem'
+
+.panel.panel-default(ng-form=form novalidate)
+    .panel-heading(bs-collapse-toggle='' ng-click='ui.loadPanel("#{form}")')
+        ignite-form-panel-chevron
+        label(id='nodeFilter-title') Node filter
+        ignite-form-field-tooltip.tipLabel
+            | Determines on what nodes the cache should be started
+        ignite-form-revert
+    .panel-collapse(role='tabpanel' bs-collapse-target id=form)
+        .panel-body(ng-if='ui.isPanelLoaded("#{form}")')
+            .col-sm-6
+                .settings-row
+                    -var nodeFilter = model + '.nodeFilter';
+                    -var nodeFilterKind = nodeFilter + '.kind';
+
+                    +dropdown('Node filter:', nodeFilterKind, '"nodeFilter"', 'true', 'Not set',
+                        '[\
+                            {value: "IGFS", label: "IGFS nodes"},\
+                            {value: "OnNodes", label: "Specified nodes"},\
+                            {value: "Custom", label: "Custom"},\
+                            {value: undefined, label: "Not set"}\
+                        ]',
+                        'Node filter variant'
+                    )
+                .settings-row(ng-show=nodeFilterKind)
+                    div(ng-show='#{nodeFilterKind} === "IGFS"')
+                        -var igfsNodeFilter = nodeFilter + '.IGFS'
+                        -var required = nodeFilterKind + ' === "IGFS"'
+
+                        //(lbl, model, name, enabled, required, placeholder, options, tip)
+                        +dropdown-required-empty('IGFS:', igfsNodeFilter + '.igfs', '"igfsNodeFilter"', 'true', required,
+                            'Choose IGFS', 'No IGFS configured', 'igfss', 'Select IGFS to filter nodes')
+                    div(ng-show='#{nodeFilterKind} === "Custom"')
+                        -var customNodeFilter = nodeFilter + '.Custom'
+                        -var required = nodeFilterKind + ' === "Custom"'
+
+                        +java-class('Class name:', customNodeFilter + '.className', '"customNodeFilter"',
+                            'true', required, 'Class name of custom node filter implementation')
+                    div(ng-show='#{nodeFilterKind} === "OnNodes"')
+                        -var nodeSetFilter = nodeFilter + '.OnNodes.nodeIds'
+
+                        +ignite-form-group(ng-form=form ng-model=nodeSetFilter)
+                            -var uniqueTip = 'Such node ID already exists!'
+
+                            ignite-form-field-label
+                                | Node IDs
+                            ignite-form-group-tooltip
+                                | Set of node IDs to deploy cache
+                            ignite-form-group-add(ng-click='group.add = [{}]')
+                                | Add new node ID
+
+                            .group-content(ng-if='#{nodeSetFilter}.length')
+                                -var model = 'obj.model';
+                                -var name = '"edit" + $index'
+                                -var valid = form + '[' + name + '].$valid'
+                                -var save = nodeSetFilter + '[$index] = ' + model
+
+                                div(ng-repeat='model in #{nodeSetFilter} track by $index' ng-init='obj = {}')
+                                    label.col-xs-12.col-sm-12.col-md-12
+                                        .indexField
+                                            | {{ $index+1 }})
+                                        +table-remove-button(nodeSetFilter, 'Remove node ID')
+
+                                        span(ng-hide='field.edit')
+                                            a.labelFormField(ng-click='field.edit = true; #{model} = model;') {{ model }}
+                                        span(ng-if='field.edit' ng-init='#{field} = model')
+                                            +table-uuid-field(name, model, nodeSetFilter, valid, save, false, true)
+                                                +table-save-button(valid, save, false)
+                                                +unique-feedback(name, uniqueTip)
+                                                +uuid-feedback(name)
+
+                            .group-content(ng-repeat='field in group.add')
+                                -var model = 'new';
+                                -var name = '"new"'
+                                -var valid = form + '[' + name + '].$valid'
+                                -var save = nodeSetFilter + '.push(' + model + ')'
+
+                                div
+                                    label.col-xs-12.col-sm-12.col-md-12
+                                        +table-uuid-field(name, model, nodeSetFilter, valid, save, true, true)
+                                            +table-save-button(valid, save, true)
+                                            +unique-feedback(name, uniqueTip)
+                                            +uuid-feedback(name)
+                            .group-content-empty(id='nodeSetFilter' ng-if='!(#{nodeSetFilter}.length) && !group.add.length')
+                                | Not defined
+
+            .col-sm-6
+                +preview-xml-java(model, 'cacheNodeFilter', 'igfss')

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/frontend/app/modules/states/configuration/caches/query.jade
----------------------------------------------------------------------
diff --git a/modules/web-console/frontend/app/modules/states/configuration/caches/query.jade b/modules/web-console/frontend/app/modules/states/configuration/caches/query.jade
new file mode 100644
index 0000000..c83114b
--- /dev/null
+++ b/modules/web-console/frontend/app/modules/states/configuration/caches/query.jade
@@ -0,0 +1,95 @@
+//-
+    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.jade
+
+-var form = 'query'
+-var model = 'backupItem'
+
+.panel.panel-default(ng-form=form novalidate)
+    .panel-heading(bs-collapse-toggle='' ng-click='ui.loadPanel("#{form}")')
+        ignite-form-panel-chevron
+        label Queries & Indexing
+        ignite-form-field-tooltip.tipLabel
+            | Cache queries settings
+        ignite-form-revert
+    .panel-collapse(role='tabpanel' bs-collapse-target id=form)
+        .panel-body(ng-if='ui.isPanelLoaded("#{form}")')
+            .col-sm-6
+                .settings-row
+                    +text('SQL schema name:', model + '.sqlSchema', '"sqlSchema"', 'false', 'Input schema name', 'Schema name for cache according to SQL ANSI-99')
+                .settings-row
+                    +number('On-heap cache for off-heap indexes:', model + '.sqlOnheapRowCacheSize', '"sqlOnheapRowCacheSize"', 'true', '10240', '1',
+                        'Number of SQL rows which will be cached onheap to avoid deserialization on each SQL index access')
+                .settings-row
+                    +number('Long query timeout:', model + '.longQueryWarningTimeout', '"longQueryWarningTimeout"', 'true', '3000', '0',
+                        'Timeout in milliseconds after which long query warning will be printed')
+                .settings-row
+                    -var form = 'querySqlFunctionClasses';
+                    -var sqlFunctionClasses = model + '.sqlFunctionClasses';
+
+                    +ignite-form-group(ng-form=form ng-model=sqlFunctionClasses)
+                        ignite-form-field-label
+                            | SQL functions
+                        ignite-form-group-tooltip
+                            | Collections of classes with user-defined functions for SQL queries
+                        ignite-form-group-add(ng-click='group.add = [{}]')
+                            | Add new user-defined functions for SQL queries
+
+                        -var uniqueTip = 'SQL function with such class name already exists!'
+
+                        .group-content(ng-if='#{sqlFunctionClasses}.length')
+                            -var model = 'obj.model';
+                            -var name = '"edit" + $index'
+                            -var valid = form + '[' + name + '].$valid'
+                            -var save = sqlFunctionClasses + '[$index] = ' + model
+
+                            div(ng-repeat='model in #{sqlFunctionClasses} track by $index' ng-init='obj = {}')
+                                label.col-xs-12.col-sm-12.col-md-12
+                                    .indexField
+                                        | {{ $index+1 }})
+                                    +table-remove-button(sqlFunctionClasses, 'Remove user-defined function')
+
+                                    span(ng-hide='field.edit')
+                                        a.labelFormField(ng-click='field.edit = true; #{model} = model;') {{ model }}
+                                    span(ng-if='field.edit')
+                                        +table-java-class-field('SQL function', name, model, sqlFunctionClasses, valid, save, false)
+                                            +table-save-button(valid, save, false)
+                                            +unique-feedback(name, uniqueTip)
+
+                        .group-content(ng-repeat='field in group.add')
+                            -var model = 'new';
+                            -var name = '"new"'
+                            -var valid = form + '[' + name + '].$valid'
+                            -var save = sqlFunctionClasses + '.push(' + model + ')'
+
+                            div
+                                label.col-xs-12.col-sm-12.col-md-12
+                                    +table-java-class-field('SQL function', name, model, sqlFunctionClasses, valid, save, true)
+                                        +table-save-button(valid, save, true)
+                                        +unique-feedback(name, uniqueTip)
+
+                        .group-content-empty(ng-if='!(#{sqlFunctionClasses}.length) && !group.add.length')
+                            | Not defined
+                .settings-row
+                    +checkbox('Snapshotable index', model + '.snapshotableIndex', '"snapshotableIndex"',
+                        'Flag indicating whether SQL indexes should support snapshots')
+                .settings-row
+                    +checkbox('Escape table and filed names', model + '.sqlEscapeAll', '"sqlEscapeAll"',
+                        'If set then all the SQL table and field names will be escaped with double quotes<br/>\
+                        This enforces case sensitivity for field names and also allows having special characters in table and field names')
+            .col-sm-6
+                +preview-xml-java(model, 'cacheQuery', 'domains')

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/frontend/app/modules/states/configuration/caches/rebalance.jade
----------------------------------------------------------------------
diff --git a/modules/web-console/frontend/app/modules/states/configuration/caches/rebalance.jade b/modules/web-console/frontend/app/modules/states/configuration/caches/rebalance.jade
new file mode 100644
index 0000000..6cf2d33
--- /dev/null
+++ b/modules/web-console/frontend/app/modules/states/configuration/caches/rebalance.jade
@@ -0,0 +1,65 @@
+//-
+    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.jade
+
+-var form = 'rebalance'
+-var model = 'backupItem'
+
+.panel.panel-default(ng-form=form novalidate ng-hide='#{model}.cacheMode === "LOCAL"')
+    .panel-heading(bs-collapse-toggle='' ng-click='ui.loadPanel("#{form}")')
+        ignite-form-panel-chevron
+        label Rebalance
+        ignite-form-field-tooltip.tipLabel
+            | Cache rebalance settings
+        ignite-form-revert
+    .panel-collapse(role='tabpanel' bs-collapse-target id=form)
+        .panel-body(ng-if='ui.isPanelLoaded("#{form}")')
+            .col-sm-6
+                .settings-row
+                    +dropdown('Mode:', model + '.rebalanceMode', '"rebalanceMode"', 'true', 'ASYNC',
+                        '[\
+                            {value: "SYNC", label: "SYNC"},\
+                            {value: "ASYNC", label: "ASYNC"},\
+                            {value: "NONE", label: "NONE"}\
+                        ]',
+                        'Rebalance modes\
+                        <ul>\
+                            <li>Synchronous - in this mode distributed caches will not start until all necessary data is loaded from other available grid nodes</li>\
+                            <li>Asynchronous - in this mode distributed caches will start immediately and will load all necessary data from other available grid nodes in the background</li>\
+                            <li>None - in this mode no rebalancing will take place which means that caches will be either loaded on demand from persistent store whenever data is accessed, or will be populated explicitly</li>\
+                        </ul>')
+                    .settings-row
+                        +number('Batch size:', model + '.rebalanceBatchSize', '"rebalanceBatchSize"', 'true', '512 * 1024', '1',
+                            'Size (in bytes) to be loaded within a single rebalance message<br/>\
+                            Rebalancing algorithm will split total data set on every node into multiple batches prior to sending data')
+                    .settings-row
+                        +number('Batches prefetch count:', model + '.rebalanceBatchesPrefetchCount', '"rebalanceBatchesPrefetchCount"', 'true', '2', '1',
+                            'Number of batches generated by supply node at rebalancing start')
+                    .settings-row
+                        +number('Order:', model + '.rebalanceOrder', '"rebalanceOrder"', 'true', '0', Number.MIN_SAFE_INTEGER,
+                            'If cache rebalance order is positive, rebalancing for this cache will be started only when rebalancing for all caches with smaller rebalance order (except caches with rebalance order 0) will be completed')
+                    .settings-row
+                        +number('Delay:', model + '.rebalanceDelay', '"rebalanceDelay"', 'true', '0', '0',
+                            'Delay in milliseconds upon a node joining or leaving topology (or crash) after which rebalancing should be started automatically')
+                    .settings-row
+                        +number('Timeout:', model + '.rebalanceTimeout', '"rebalanceTimeout"', 'true', '10000', '0',
+                            'Rebalance timeout in milliseconds')
+                    .settings-row
+                        +number('Throttle:', model + '.rebalanceThrottle', '"rebalanceThrottle"', 'true', '0', '0',
+                            'Time in milliseconds to wait between rebalance messages to avoid overloading of CPU or network')
+            .col-sm-6
+                +preview-xml-java(model, 'cacheRebalance')

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/frontend/app/modules/states/configuration/caches/server-near-cache.jade
----------------------------------------------------------------------
diff --git a/modules/web-console/frontend/app/modules/states/configuration/caches/server-near-cache.jade b/modules/web-console/frontend/app/modules/states/configuration/caches/server-near-cache.jade
new file mode 100644
index 0000000..74f500b
--- /dev/null
+++ b/modules/web-console/frontend/app/modules/states/configuration/caches/server-near-cache.jade
@@ -0,0 +1,51 @@
+//-
+    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.jade
+
+-var form = 'serverNearCache'
+-var model = 'backupItem'
+
+.panel.panel-default(ng-form=form novalidate ng-show='#{model}.cacheMode === "PARTITIONED"')
+    .panel-heading(bs-collapse-toggle='' ng-click='ui.loadPanel("#{form}")')
+        ignite-form-panel-chevron
+        label Server near cache
+        ignite-form-field-tooltip.tipLabel
+            | Near cache settings#[br]
+            | Near cache is a small local cache that stores most recently or most frequently accessed data#[br]
+            | Should be used in case when it is impossible to send computations to remote nodes
+        ignite-form-revert
+    .panel-collapse(role='tabpanel' bs-collapse-target id=form)
+        .panel-body(ng-if='ui.isPanelLoaded("#{form}")')
+            .col-sm-6
+                -var enabled = model + '.nearCacheEnabled'
+                -var nearCfg = model + '.nearConfiguration'
+
+                .settings-row
+                    +checkbox('Enabled', enabled, '"nearCacheEnabled"', 'Flag indicating whether to configure near cache')
+                .settings-row
+                    +number('Start size:', nearCfg + '.nearStartSize', '"nearStartSize"', enabled, '375000', '0',
+                        'Initial cache size for near cache which will be used to pre-create internal hash table after start')
+                .settings-row
+                    +evictionPolicy(model + '.nearConfiguration.nearEvictionPolicy', '"nearCacheEvictionPolicy"', enabled, 'false',
+                        'Near cache eviction policy\
+                        <ul>\
+                            <li>Least Recently Used (LRU) - Eviction policy based on LRU algorithm and supports batch eviction</li>\
+                            <li>First In First Out (FIFO) - Eviction policy based on FIFO algorithm and supports batch eviction</li>\
+                            <li>SORTED - Eviction policy which will select the minimum cache entry for eviction</li>\
+                        </ul>')
+            .col-sm-6
+                +preview-xml-java(model, 'cacheServerNearCache')

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/frontend/app/modules/states/configuration/caches/statistics.jade
----------------------------------------------------------------------
diff --git a/modules/web-console/frontend/app/modules/states/configuration/caches/statistics.jade b/modules/web-console/frontend/app/modules/states/configuration/caches/statistics.jade
new file mode 100644
index 0000000..027a2bd
--- /dev/null
+++ b/modules/web-console/frontend/app/modules/states/configuration/caches/statistics.jade
@@ -0,0 +1,39 @@
+//-
+    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.jade
+
+-var form = 'statistics'
+-var model = 'backupItem'
+
+.panel.panel-default(ng-form=form novalidate)
+    .panel-heading(bs-collapse-toggle='' ng-click='ui.loadPanel("#{form}")')
+        ignite-form-panel-chevron
+        label Statistics
+        ignite-form-field-tooltip.tipLabel
+            | Cache statistics and management settings
+        ignite-form-revert
+    .panel-collapse(role='tabpanel' bs-collapse-target id=form)
+        .panel-body(ng-if='ui.isPanelLoaded("#{form}")')
+            .col-sm-6
+                .settings-row
+                    +checkbox('Statistics enabled', model + '.statisticsEnabled', '"statisticsEnabled"', 'Flag indicating whether statistics gathering is enabled on this cache')
+                .settings-row
+                    +checkbox('Management enabled', model + '.managementEnabled', '"managementEnabled"',
+                    'Flag indicating whether management is enabled on this cache<br/>\
+                    If enabled the CacheMXBean for each cache is registered in the platform MBean server')
+            .col-sm-6
+                +preview-xml-java(model, 'cacheStatistics')

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/frontend/app/modules/states/configuration/caches/store.jade
----------------------------------------------------------------------
diff --git a/modules/web-console/frontend/app/modules/states/configuration/caches/store.jade b/modules/web-console/frontend/app/modules/states/configuration/caches/store.jade
new file mode 100644
index 0000000..84752d6
--- /dev/null
+++ b/modules/web-console/frontend/app/modules/states/configuration/caches/store.jade
@@ -0,0 +1,244 @@
+//-
+    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.jade
+
+-var form = 'store'
+-var model = 'backupItem'
+
+mixin hibernateField(name, model, items, valid, save, newItem)
+    -var reset = newItem ? 'group.add = []' : 'field.edit = false'
+
+    -var resetOnEnter = newItem ? '(stopblur = true) && (group.add = [{}])' : '(field.edit = false)'
+    -var onEnter = valid + ' && (' + save + '); ' + valid + ' && ' + resetOnEnter + ';'
+
+    -var resetOnBlur = newItem ? '!stopblur && (group.add = [])' : 'field.edit = false'
+    -var onBlur = valid + ' && ( ' + save + '); ' + resetOnBlur + ';'
+
+    if block
+        block
+
+    .input-tip
+        +ignite-form-field-input(name, model, false, 'true', 'key=value')(
+            data-ignite-property-unique=items
+            data-ignite-property-value-specified
+            data-ignite-form-field-input-autofocus='true'
+
+            ng-blur=onBlur
+            ignite-on-enter=onEnter
+            ignite-on-escape=onEscape
+        )
+
+.panel.panel-default(ng-form=form novalidate)
+    .panel-heading(bs-collapse-toggle='' ng-click='ui.loadPanel("#{form}")')
+        ignite-form-panel-chevron
+        label Store
+        ignite-form-field-tooltip.tipLabel
+            | Cache store settings
+        ignite-form-revert
+    .panel-collapse(role='tabpanel' bs-collapse-target id=form)
+        .panel-body(ng-if='ui.isPanelLoaded("#{form}")')
+            .col-sm-6
+                .settings-row
+                    -var storeFactory = model + '.cacheStoreFactory';
+                    -var storeFactoryKind = storeFactory + '.kind';
+
+                    +dropdown('Store factory:', storeFactoryKind, '"cacheStoreFactory"', 'true', 'Not set',
+                        '[\
+                            {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"}\
+                        ]',
+                        'Factory for persistent storage for cache data\
+                        <ul>\
+                            <li>JDBC POJO store factory - Objects are stored in underlying database by using java beans mapping description via reflection backed by JDBC</li>\
+                            <li>JDBC BLOB store factory - Objects are stored in underlying database in BLOB format backed by JDBC</li>\
+                            <li>Hibernate BLOB store factory - Objects are stored in underlying database in BLOB format backed by Hibernate</li>\
+                        </ul>'
+                    )
+                    span(ng-show=storeFactoryKind ng-init='__.expanded = true')
+                        a.customize(ng-show='__.expanded' ng-click='__.expanded = false') Hide settings
+                        a.customize(ng-hide='__.expanded' ng-click='__.expanded = true') Show settings
+                        .panel-details(ng-show='__.expanded')
+                            div(ng-show='#{storeFactoryKind} === "CacheJdbcPojoStoreFactory"')
+                                -var pojoStoreFactory = storeFactory + '.CacheJdbcPojoStoreFactory'
+                                -var required = storeFactoryKind + ' === "CacheJdbcPojoStoreFactory"'
+
+                                .details-row
+                                    +text('Data source bean name:', pojoStoreFactory + '.dataSourceBean',
+                                        '"pojoDataSourceBean"', required, 'Input bean name',
+                                        'Name of the data source bean in Spring context')
+                                .details-row
+                                    +dialect('Dialect:', pojoStoreFactory + '.dialect', '"pojoDialect"', required,
+                                        'Dialect of SQL implemented by a particular RDBMS:', 'Generic JDBC dialect',
+                                        'Choose JDBC dialect')
+                            div(ng-show='#{storeFactoryKind} === "CacheJdbcBlobStoreFactory"')
+                                -var blobStoreFactory = storeFactory + '.CacheJdbcBlobStoreFactory'
+                                -var blobStoreFactoryVia = blobStoreFactory + '.connectVia'
+
+                                .details-row
+                                    +dropdown('Connect via:', blobStoreFactoryVia, '"connectVia"', 'true', 'Choose connection method',
+                                        '[\
+                                            {value: "URL", label: "URL"},\
+                                            {value: "DataSource", label: "Data source"}\
+                                        ]',
+                                        'You can connect to database via:\
+                                        <ul>\
+                                            <li>JDBC URL, for example: jdbc:h2:mem:myDatabase</li>\
+                                            <li>Configured data source</li>\
+                                        </ul>')
+                                div(ng-show='#{blobStoreFactoryVia} === "URL"')
+                                    -var required = storeFactoryKind + ' === "CacheJdbcBlobStoreFactory" && ' + blobStoreFactoryVia + ' === "URL"'
+
+                                    .details-row
+                                        +text('Connection URL:', blobStoreFactory + '.connectionUrl', '"connectionUrl"', required, 'Input URL',
+                                            'URL for database access, for example: jdbc:h2:mem:myDatabase')
+                                    .details-row
+                                        +text('User:', blobStoreFactory + '.user', '"user"', required, 'Input user name', 'User name for database access')
+                                    .details-row
+                                        label Note, password will be generated as stub
+                                div(ng-show='#{blobStoreFactoryVia} !== "URL"')
+                                    -var required = storeFactoryKind + ' === "CacheJdbcBlobStoreFactory" && ' + blobStoreFactoryVia + '!== "URL"'
+
+                                    .details-row
+                                        +text('Data source bean name:', blobStoreFactory + '.dataSourceBean', '"blobDataSourceBean"', required, 'Input bean name',
+                                            'Name of the data source bean in Spring context')
+                                    .details-row
+                                        +dialect('Database:', blobStoreFactory + '.dialect', '"blobDialect"', required, 'Supported databases:', 'Generic database', 'Choose database')
+                                .details-row
+                                    +checkbox('Init schema', blobStoreFactory + '.initSchema', '"initSchema"',
+                                        'Flag indicating whether DB schema should be initialized by Ignite (default behaviour) or was explicitly created by user')
+                                .details-row
+                                    +text('Create query:', blobStoreFactory + '.createTableQuery', '"createTableQuery"', 'false', 'SQL for table creation',
+                                        'Query for table creation in underlying database<br/>\
+                                        Default value: create table if not exists ENTRIES (key binary primary key, val binary)')
+                                .details-row
+                                    +text('Load query:', blobStoreFactory + '.loadQuery', '"loadQuery"', 'false', 'SQL for load entry',
+                                        'Query for entry load from underlying database<br/>\
+                                        Default value: select * from ENTRIES where key=?')
+                                .details-row
+                                    +text('Insert query:', blobStoreFactory + '.insertQuery', '"insertQuery"', 'false', 'SQL for insert entry',
+                                        'Query for insert entry into underlying database<br/>\
+                                        Default value: insert into ENTRIES (key, val) values (?, ?)')
+                                .details-row
+                                    +text('Update query:', blobStoreFactory + '.updateQuery', '"updateQuery"', 'false', 'SQL for update entry',
+                                        'Query for update entry in underlying database<br/>\
+                                        Default value: update ENTRIES set val=? where key=?')
+                                .details-row
+                                    +text('Delete query:', blobStoreFactory + '.deleteQuery', '"deleteQuery"', 'false', 'SQL for delete entry',
+                                        'Query for delete entry from underlying database<br/>\
+                                        Default value: delete from ENTRIES where key=?')
+
+                            div(ng-show='#{storeFactoryKind} === "CacheHibernateBlobStoreFactory"')
+                                -var hibernateStoreFactory = storeFactory + '.CacheHibernateBlobStoreFactory'
+                                -var hibernateProperties = hibernateStoreFactory + '.hibernateProperties'
+
+                                .details-row
+                                    +ignite-form-group(ng-form=form ng-model=hibernateProperties)
+                                        ignite-form-field-label
+                                            | Hibernate properties
+                                        ignite-form-group-tooltip
+                                            | List of Hibernate properties#[br]
+                                            | For example: connection.url=jdbc:h2:mem:exampleDb
+                                        ignite-form-group-add(ng-click='group.add = [{}]')
+                                            | Add new Hibernate property
+
+                                        -var tipUnique = 'Property with such key already exists!'
+                                        -var tipPropertySpecified = 'Property should be present in format key=value!'
+
+                                        .group-content(ng-if='#{hibernateProperties}.length')
+                                            -var model = 'obj.model';
+                                            -var name = '"edit" + $index'
+                                            -var valid = form + '[' + name + '].$valid'
+                                            -var save = hibernateProperties + '[$index] = ' + model
+
+                                            div(ng-repeat='model in #{hibernateProperties} track by $index' ng-init='obj = {}')
+                                                label.col-xs-12.col-sm-12.col-md-12
+                                                    .indexField
+                                                        | {{ $index+1 }})
+                                                    +table-remove-button(hibernateProperties, 'Remove Hibernate property')
+
+                                                    span(ng-hide='field.edit')
+                                                        a.labelFormField(ng-click='field.edit = true; #{model} = model;') {{ model }}
+                                                    span(ng-if='field.edit')
+                                                        +hibernateField(name, model, hibernateProperties, valid, save, false)
+                                                            +table-save-button(valid, save, false)
+                                                            +form-field-feedback(name, 'ignitePropertyUnique', tipUnique)
+                                                            +form-field-feedback(name, 'ignitePropertyValueSpecified', tipPropertySpecified)
+
+                                        .group-content(ng-repeat='field in group.add')
+                                            -var model = 'new';
+                                            -var name = '"new"'
+                                            -var valid = form + '[' + name + '].$valid'
+                                            -var save = hibernateProperties + '.push(' + model + ')'
+
+                                            div
+                                                label.col-xs-12.col-sm-12.col-md-12
+                                                    +hibernateField(name, model, hibernateProperties, valid, save, true)
+                                                        +table-save-button(valid, save, true)
+                                                        +form-field-feedback(name, 'ignitePropertyUnique', tipUnique)
+                                                        +form-field-feedback(name, 'ignitePropertyValueSpecified', tipPropertySpecified)
+                                        .group-content-empty(ng-if='!(#{hibernateProperties}.length) && !group.add.length')
+                                            | Not defined
+
+                .settings-row
+                    +checkbox('Keep binary in store', model + '.storeKeepBinary', '"storeKeepBinary"',
+                        'Flag indicating that CacheStore implementation is working with binary objects instead of Java objects')
+                .settings-row
+                    +checkbox('Load previous value', model + '.loadPreviousValue', '"loadPreviousValue"',
+                        'Flag indicating whether value should be loaded from store if it is not in the cache for following cache operations: \
+                        <ul> \
+                            <li>IgniteCache.putIfAbsent()</li> \
+                            <li>IgniteCache.replace()</li> \
+                            <li>IgniteCache.remove()</li> \
+                            <li>IgniteCache.getAndPut()</li> \
+                            <li>IgniteCache.getAndRemove()</li> \
+                            <li>IgniteCache.getAndReplace()</li> \
+                            <li> IgniteCache.getAndPutIfAbsent()</li>\
+                        </ul>')
+                .settings-row
+                    +checkbox('Read-through', model + '.readThrough', '"readThrough"', 'Flag indicating whether read-through caching should be used')
+                .settings-row
+                    +checkbox('Write-through', model + '.writeThrough', '"writeThrough"', 'Flag indicating whether write-through caching should be used')
+                .settings-row
+                    +ignite-form-group
+                        ignite-form-field-label
+                            | Write-behind
+                        ignite-form-group-tooltip
+                            | Cache write-behind settings#[br]
+                            | Write-behind is a special mode when updates to cache accumulated and then asynchronously flushed to persistent store as a bulk operation
+                        .group-content
+                            -var enabled = model + '.writeBehindEnabled'
+
+                            .details-row
+                                +checkbox('Enabled', enabled, '"writeBehindEnabled"', 'Flag indicating whether Ignite should use write-behind behaviour for the cache store')
+                            .details-row
+                                +number('Batch size:', model + '.writeBehindBatchSize', '"writeBehindBatchSize"', enabled, '512', '1',
+                                    'Maximum batch size for write-behind cache store operations<br/>\
+                                     Store operations(get or remove) are combined in a batch of this size to be passed to cache store')
+                            .details-row
+                                +number('Flush size:', model + '.writeBehindFlushSize', '"writeBehindFlushSize"', enabled, '10240', '0',
+                                    'Maximum size of the write-behind cache<br/>\
+                                     If cache size exceeds this value, all cached items are flushed to the cache store and write cache is cleared')
+                            .details-row
+                                +number('Flush frequency:', model + '.writeBehindFlushFrequency', '"writeBehindFlushFrequency"', enabled, '5000', '0',
+                                    'Frequency with which write-behind cache is flushed to the cache store in milliseconds')
+                            .details-row
+                                +number('Flush threads count:', model + '.writeBehindFlushThreadCount', '"writeBehindFlushThreadCount"', enabled, '1', '1',
+                                    'Number of threads that will perform cache flushing')
+            .col-sm-6
+                +preview-xml-java(model, 'cacheStore', 'domains')

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/frontend/app/modules/states/configuration/clusters/atomic.jade
----------------------------------------------------------------------
diff --git a/modules/web-console/frontend/app/modules/states/configuration/clusters/atomic.jade b/modules/web-console/frontend/app/modules/states/configuration/clusters/atomic.jade
new file mode 100644
index 0000000..c4ef88e
--- /dev/null
+++ b/modules/web-console/frontend/app/modules/states/configuration/clusters/atomic.jade
@@ -0,0 +1,53 @@
+//-
+    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.jade
+
+-var form = 'atomics'
+-var model = 'backupItem.atomicConfiguration'
+
+.panel.panel-default(ng-form=form novalidate)
+    .panel-heading(bs-collapse-toggle='' ng-click='ui.loadPanel("#{form}")')
+        ignite-form-panel-chevron
+        label Atomic configuration
+        ignite-form-field-tooltip.tipLabel
+            | Configuration for atomic data structures#[br]
+            | Atomics are distributed across the cluster, essentially enabling performing atomic operations (such as increment-and-get or compare-and-set) with the same globally-visible value
+        ignite-form-revert 
+    .panel-collapse(role='tabpanel' bs-collapse-target='' id=form)
+        .panel-body(ng-if='ui.isPanelLoaded("#{form}")')
+            .col-sm-6
+                .settings-row
+                    +dropdown('Cache mode:', model + '.cacheMode', '"cacheMode"', 'true', 'PARTITIONED',
+                        '[\
+                            {value: "LOCAL", label: "LOCAL"},\
+                            {value: "REPLICATED", label: "REPLICATED"},\
+                            {value: "PARTITIONED", label: "PARTITIONED"}\
+                        ]',
+                        'Cache modes:\
+                        <ul>\
+                            <li>Partitioned - in this mode the overall key set will be divided into partitions and all partitions will be split equally between participating nodes</li>\
+                            <li>Replicated - in this mode all the keys are distributed to all participating nodes</li>\
+                            <li>Local - in this mode caches residing on different grid nodes will not know about each other</li>\
+                        </ul>')
+                .settings-row
+                    +number('Sequence reserve:', model + '.atomicSequenceReserveSize', '"atomicSequenceReserveSize"', 'true', '1000', '0',
+                        'Default number of sequence values reserved for IgniteAtomicSequence instances<br/>\
+                        After a certain number has been reserved, consequent increments of sequence will happen locally, without communication with other nodes, until the next reservation has to be made')
+                .settings-row(ng-show='!(#{model}.cacheMode && #{model}.cacheMode != "PARTITIONED")')
+                    +number('Backups:', model + '.backups', '"backups"', 'true', '0', '0', 'Number of backup nodes')
+            .col-sm-6
+                +preview-xml-java(model, 'clusterAtomics')

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/frontend/app/modules/states/configuration/clusters/attributes.jade
----------------------------------------------------------------------
diff --git a/modules/web-console/frontend/app/modules/states/configuration/clusters/attributes.jade b/modules/web-console/frontend/app/modules/states/configuration/clusters/attributes.jade
new file mode 100644
index 0000000..29e7a79
--- /dev/null
+++ b/modules/web-console/frontend/app/modules/states/configuration/clusters/attributes.jade
@@ -0,0 +1,57 @@
+//-
+    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.jade
+
+-var form = 'attributes'
+-var model = 'backupItem'
+-var userAttributes = model + '.attributes'
+
+.panel.panel-default(ng-form=form novalidate)
+    .panel-heading(bs-collapse-toggle ng-click='ui.loadPanel("#{form}")')
+        ignite-form-panel-chevron
+        label User attributes
+        ignite-form-field-tooltip.tipLabel
+            | Configuration for Ignite user attributes
+        ignite-form-revert
+    .panel-collapse(role='tabpanel' bs-collapse-target id=form)
+        .panel-body(ng-if='ui.isPanelLoaded("#{form}")')
+            .col-sm-6
+                .settings-row
+                    +ignite-form-group(ng-model='#{userAttributes}' ng-form='#{form}')
+                        ignite-form-field-label
+                            | User attributes
+                        ignite-form-group-tooltip
+                            | User-defined attributes to add to node
+                        ignite-form-group-add(ng-click='tableNewItem(attributesTbl)')
+                            | Add user attribute
+                        .group-content-empty(ng-if='!((#{userAttributes} && #{userAttributes}.length > 0) || tableNewItemActive(attributesTbl))')
+                            | Not defined
+                        .group-content(ng-show='(#{userAttributes} && #{userAttributes}.length > 0) || tableNewItemActive(attributesTbl)')
+                            table.links-edit(id='attributes' st-table=userAttributes)
+                                tbody
+                                    tr(ng-repeat='item in #{userAttributes}')
+                                        td.col-sm-12(ng-show='!tableEditing(attributesTbl, $index)')
+                                            a.labelFormField(ng-click='tableStartEdit(backupItem, attributesTbl, $index)') {{item.name}} = {{item.value}}
+                                            +btn-remove('tableRemove(backupItem, attributesTbl, $index)', '"Remove attribute"')
+                                        td.col-sm-12(ng-show='tableEditing(attributesTbl, $index)')
+                                            +table-pair-edit('attributesTbl', 'cur', 'Attribute name', 'Attribute value', false, false, '{{::attributesTbl.focusId + $index}}', '$index', '=')
+                                tfoot(ng-show='tableNewItemActive(attributesTbl)')
+                                    tr
+                                        td.col-sm-12
+                                            +table-pair-edit('attributesTbl', 'new', 'Attribute name', 'Attribute value', false, false, '{{::attributesTbl.focusId + $index}}', '-1', '=')
+            .col-sm-6
+                +preview-xml-java(model, 'clusterUserAttributes')

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/frontend/app/modules/states/configuration/clusters/binary.jade
----------------------------------------------------------------------
diff --git a/modules/web-console/frontend/app/modules/states/configuration/clusters/binary.jade b/modules/web-console/frontend/app/modules/states/configuration/clusters/binary.jade
new file mode 100644
index 0000000..c63e2d9
--- /dev/null
+++ b/modules/web-console/frontend/app/modules/states/configuration/clusters/binary.jade
@@ -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.
+
+include ../../../../../app/helpers/jade/mixins.jade
+
+-var form = 'binary'
+-var model = 'backupItem.binaryConfiguration'
+-var types = model + '.typeConfigurations'
+
+//- Mixin for java name field with enabled condition.
+mixin binary-types-java-class(lbl, model, name, enabled, required, remove, autofocus, tip)
+    +java-class(lbl, model, name, enabled, required, tip)
+        if (remove)
+            +table-remove-button(types, 'Remove type configuration')
+
+.panel.panel-default(ng-form=form novalidate)
+    .panel-heading(bs-collapse-toggle ng-click='ui.loadPanel("#{form}")')
+        ignite-form-panel-chevron
+        label Binary configuration
+        ignite-form-field-tooltip.tipLabel
+            | Configuration of specific binary types
+        ignite-form-revert
+    .panel-collapse(role='tabpanel' bs-collapse-target id=form)
+        .panel-body(ng-if='ui.isPanelLoaded("#{form}")')
+            .col-sm-6
+                .settings-row
+                    +java-class('ID mapper:', model + '.idMapper', '"idMapper"', 'true', 'false',
+                        'Maps given from BinaryNameMapper type and filed name to ID that will be used by Ignite in internals<br/>\
+                        Ignite never writes full strings for field or type names. Instead, for performance reasons, Ignite writes integer hash codes for type/class and field names. It has been tested that hash code conflicts for the type/class names or the field names within the same type are virtually non - existent and, to gain performance, it is safe to work with hash codes. For the cases when hash codes for different types or fields actually do collide <b>BinaryIdMapper</b> allows to override the automatically generated hash code IDs for the type and field names')
+                .settings-row
+                    +java-class('Name mapper:', model + '.nameMapper', '"nameMapper"', 'true', 'false', 'Maps type/class and field names to different names')
+                .settings-row
+                    +java-class('Serializer:', model + '.serializer', '"serializer"', 'true', 'false', 'Class with custom serialization logic for binary objects')
+                .settings-row
+                    -var form = 'binaryTypeConfigurations';
+
+                    +ignite-form-group()
+                        ignite-form-field-label
+                            | Type configurations
+                        ignite-form-group-tooltip
+                            | Configuration properties for binary types
+                        ignite-form-group-add(ng-click='#{types}.push({})')
+                            | Add new type configuration.
+                        .group-content-empty(ng-if='!#{types}.length')
+                            | Not defined
+                        .group-content(ng-repeat='model in #{types} track by $index')
+                            hr(ng-if='$index !== 0')
+                            .settings-row
+                                +binary-types-java-class('Type name:', 'model.typeName', '"typeName" + $index', 'true', 'true', true, 'true', 'Type name')
+                            .settings-row
+                                +binary-types-java-class('ID mapper:', 'model.idMapper', '"idMapper" + $index', 'true', 'false', false, 'false',
+                                    'Maps given from BinaryNameMapper type and filed name to ID that will be used by Ignite in internals<br/>\
+                                    Ignite never writes full strings for field or type/class names. Instead, for performance reasons, Ignite writes integer hash codes for type/class and field names. It has been tested that hash code conflicts for the type/class names or the field names within the same type are virtually non - existent and, to gain performance, it is safe to work with hash codes. For the cases when hash codes for different types or fields actually do collide <b>BinaryIdMapper</b> allows to override the automatically generated hash code IDs for the type and field names')
+                            .settings-row
+                                +binary-types-java-class('Name mapper:', 'model.nameMapper', '"nameMapper" + $index', 'true', 'false', false, 'false', 'Maps type/class and field names to different names')
+                            .settings-row
+                                +binary-types-java-class('Serializer:', 'model.serializer', '"serializer" + $index', 'true', 'false', false, 'false', 'Class with custom serialization logic for binary object')
+                            .settings-row
+                                +checkbox('Enum', 'model.enum', 'enum', 'Flag indicating that this type is the enum')
+
+                .settings-row
+                    +checkbox('Compact footer', model + '.compactFooter', '"compactFooter"', 'When enabled, Ignite will not write fields metadata when serializing objects(this will increase serialization performance), because internally #[b BinaryMarshaller] already distribute metadata inside cluster')
+            .col-sm-6
+                +preview-xml-java(model, 'clusterBinary')

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/frontend/app/modules/states/configuration/clusters/cache-key-cfg.jade
----------------------------------------------------------------------
diff --git a/modules/web-console/frontend/app/modules/states/configuration/clusters/cache-key-cfg.jade b/modules/web-console/frontend/app/modules/states/configuration/clusters/cache-key-cfg.jade
new file mode 100644
index 0000000..a078bf1
--- /dev/null
+++ b/modules/web-console/frontend/app/modules/states/configuration/clusters/cache-key-cfg.jade
@@ -0,0 +1,53 @@
+//-
+    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.jade
+
+-var form = 'cacheKeyCfg'
+-var model = 'backupItem.cacheKeyConfiguration'
+-var items = model;
+
+.panel.panel-default(ng-form=form novalidate)
+    .panel-heading(bs-collapse-toggle ng-click='ui.loadPanel("#{form}")')
+        ignite-form-panel-chevron
+        label Cache key configuration
+        ignite-form-field-tooltip.tipLabel
+            | Cache key configuration allows to collocate objects in a partitioned cache based on field in cache key without explicit usage of annotations on user classes.
+        ignite-form-revert
+    .panel-collapse(role='tabpanel' bs-collapse-target id=form)
+        .panel-body(ng-if='ui.isPanelLoaded("#{form}")')
+            .col-sm-6
+                .settings-row
+                    -var form = form + 'TypeConfigurations'
+
+                    +ignite-form-group(ng-form=form ng-model=model)
+                        ignite-form-field-label
+                            | Cache key configuration
+                        ignite-form-group-tooltip
+                            | Cache key configuration
+                        ignite-form-group-add(ng-click='#{model}.push({})')
+                            | Add new cache key configuration
+                        .group-content-empty(ng-if='!#{model}.length')
+                            | Not defined
+                        .group-content(ng-repeat='model in #{model} track by $index')
+                            hr(ng-if='$index !== 0')
+                            .settings-row
+                                +java-class('Type name:', 'model.typeName', '"cacheKeyTypeName" + $index', 'true', 'true', 'Type name')
+                                    +table-remove-button(items, 'Remove cache key configuration')
+                            .settings-row
+                                +text('Affinity key field name:', 'model.affinityKeyFieldName', '"affinityKeyFieldName" + $index', true, 'Enter field name', 'Affinity key field name')
+            .col-sm-6
+                +preview-xml-java(model, 'clusterCacheKeyConfiguration')

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/frontend/app/modules/states/configuration/clusters/collision.jade
----------------------------------------------------------------------
diff --git a/modules/web-console/frontend/app/modules/states/configuration/clusters/collision.jade b/modules/web-console/frontend/app/modules/states/configuration/clusters/collision.jade
new file mode 100644
index 0000000..491e4f1
--- /dev/null
+++ b/modules/web-console/frontend/app/modules/states/configuration/clusters/collision.jade
@@ -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.
+
+include ../../../../../app/helpers/jade/mixins.jade
+
+-var form = 'collision'
+-var model = 'backupItem.collision'
+-var modelCollisionKind = model + '.kind';
+
+.panel.panel-default(ng-form=form novalidate)
+    .panel-heading(bs-collapse-toggle ng-click='ui.loadPanel("#{form}")')
+        ignite-form-panel-chevron
+        label Collision configuration
+        ignite-form-field-tooltip.tipLabel
+            | Configuration Collision SPI allows to regulate how grid jobs get executed when they arrive on a destination node for execution
+        ignite-form-revert
+    .panel-collapse(role='tabpanel' bs-collapse-target id=form)
+        .panel-body(ng-if='ui.isPanelLoaded("#{form}")')
+            .col-sm-6
+                .settings-row
+                    +dropdown('CollisionSpi:', modelCollisionKind, '"collisionKind"', 'true', '',
+                        '[\
+                            {value: "JobStealing", label: "Job stealing"},\
+                            {value: "FifoQueue", label: "FIFO queue"},\
+                            {value: "PriorityQueue", label: "Priority queue"},\
+                            {value: "Custom", label: "Custom"},\
+                            {value: "Noop", label: "Default"}\
+                        ]',
+                        'Regulate how grid jobs get executed when they arrive on a destination node for execution\
+                        <ul>\
+                            <li>Job stealing - supports job stealing from over-utilized nodes to under-utilized nodes</li>\
+                            <li>FIFO queue - jobs are ordered as they arrived</li>\
+                            <li>Priority queue - jobs are first ordered by their priority</li>\
+                            <li>Custom - custom CollisionSpi implementation</li>\
+                            <li>Default - jobs are activated immediately on arrival to mapped node</li>\
+                        </ul>')
+                .settings-row(ng-show='#{modelCollisionKind} !== "Noop"')
+                    .panel-details
+                        div(ng-show='#{modelCollisionKind} === "JobStealing"')
+                            include ./collision/job-stealing.jade
+                        div(ng-show='#{modelCollisionKind} === "FifoQueue"')
+                            include ./collision/fifo-queue.jade
+                        div(ng-show='#{modelCollisionKind} === "PriorityQueue"')
+                            include ./collision/priority-queue.jade
+                        div(ng-show='#{modelCollisionKind} === "Custom"')
+                            include ./collision/custom.jade
+            .col-sm-6
+                -var model = 'backupItem.collision'
+                +preview-xml-java(model, 'clusterCollision')

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/frontend/app/modules/states/configuration/clusters/collision/custom.jade
----------------------------------------------------------------------
diff --git a/modules/web-console/frontend/app/modules/states/configuration/clusters/collision/custom.jade b/modules/web-console/frontend/app/modules/states/configuration/clusters/collision/custom.jade
new file mode 100644
index 0000000..9238917
--- /dev/null
+++ b/modules/web-console/frontend/app/modules/states/configuration/clusters/collision/custom.jade
@@ -0,0 +1,24 @@
+//-
+    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.jade
+
+-var model = 'backupItem.collision.Custom'
+-var required = 'backupItem.collision.kind === "Custom"'
+
+div
+    .details-row
+        +java-class('Class:', model + '.class', '"collisionCustom"', 'true', required, 'CollisionSpi implementation class')

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/frontend/app/modules/states/configuration/clusters/collision/fifo-queue.jade
----------------------------------------------------------------------
diff --git a/modules/web-console/frontend/app/modules/states/configuration/clusters/collision/fifo-queue.jade b/modules/web-console/frontend/app/modules/states/configuration/clusters/collision/fifo-queue.jade
new file mode 100644
index 0000000..f16363d
--- /dev/null
+++ b/modules/web-console/frontend/app/modules/states/configuration/clusters/collision/fifo-queue.jade
@@ -0,0 +1,27 @@
+//-
+    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.jade
+
+-var model = 'backupItem.collision.FifoQueue'
+
+div
+    .details-row
+        +number('Parallel jobs number:', model + '.parallelJobsNumber', '"fifoParallelJobsNumber"', 'true', 'availableProcessors * 2', '1',
+            'Number of jobs that can be executed in parallel')
+    .details-row
+        +number('Wait jobs number:', model + '.waitingJobsNumber', '"fifoWaitingJobsNumber"', 'true', 'Integer.MAX_VALUE', '0',
+            'Maximum number of jobs that are allowed to wait in waiting queue')

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/frontend/app/modules/states/configuration/clusters/collision/job-stealing.jade
----------------------------------------------------------------------
diff --git a/modules/web-console/frontend/app/modules/states/configuration/clusters/collision/job-stealing.jade b/modules/web-console/frontend/app/modules/states/configuration/clusters/collision/job-stealing.jade
new file mode 100644
index 0000000..3e6d428
--- /dev/null
+++ b/modules/web-console/frontend/app/modules/states/configuration/clusters/collision/job-stealing.jade
@@ -0,0 +1,63 @@
+//-
+    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.jade
+
+-var model = 'backupItem.collision.JobStealing'
+-var stealingAttributes = model + '.stealingAttributes'
+
+div
+    .details-row
+        +number('Active jobs threshold:', model + '.activeJobsThreshold', '"jsActiveJobsThreshold"', 'true', '95', '0',
+            'Number of jobs that can be executed in parallel')
+    .details-row
+        +number('Wait jobs threshold:', model + '.waitJobsThreshold', '"jsWaitJobsThreshold"', 'true', '0', '0',
+            'Job count threshold at which this node will start stealing jobs from other nodes')
+    .details-row
+        +number('Message expire time:', model + '.messageExpireTime', '"jsMessageExpireTime"', 'true', '1000', '1',
+            'Message expire time in ms')
+    .details-row
+        +number('Maximum stealing attempts:', model + '.maximumStealingAttempts', '"jsMaximumStealingAttempts"', 'true', '5', '1',
+            'Maximum number of attempts to steal job by another node')
+    .details-row
+        +checkbox('Stealing enabled', model + '.stealingEnabled', '"jsStealingEnabled"',
+            'Node should attempt to steal jobs from other nodes')
+    .details-row
+        +java-class('External listener:', model + '.externalCollisionListener', '"jsExternalCollisionListener"', 'true', 'false',
+            'Listener to be set for notification of external collision events')
+    .details-row
+        +ignite-form-group(ng-model='#{stealingAttributes}' ng-form='#{form}')
+            ignite-form-field-label
+                | Stealing attributes
+            ignite-form-group-tooltip
+                | Configuration parameter to enable stealing to/from only nodes that have these attributes set
+            ignite-form-group-add(ng-click='tableNewItem(stealingAttributesTbl)')
+                | Add stealing attribute
+            .group-content-empty(ng-if='!((#{stealingAttributes} && #{stealingAttributes}.length > 0) || tableNewItemActive(stealingAttributesTbl))')
+                | Not defined
+            .group-content(ng-show='(#{stealingAttributes} && #{stealingAttributes}.length > 0) || tableNewItemActive(stealingAttributesTbl)')
+                table.links-edit(id='attributes' st-table=stealingAttributes)
+                    tbody
+                        tr(ng-repeat='item in #{stealingAttributes} track by $index')
+                            td.col-sm-12(ng-show='!tableEditing(stealingAttributesTbl, $index)')
+                                a.labelFormField(ng-click='tableStartEdit(backupItem, stealingAttributesTbl, $index)') {{item.name}} = {{item.value}}
+                                +btn-remove('tableRemove(backupItem, stealingAttributesTbl, $index)', '"Remove attribute"')
+                            td.col-sm-12(ng-show='tableEditing(stealingAttributesTbl, $index)')
+                                +table-pair-edit('stealingAttributesTbl', 'cur', 'Attribute name', 'Attribute value', false, false, '{{::stealingAttributesTbl.focusId + $index}}', '$index', '=')
+                    tfoot(ng-show='tableNewItemActive(stealingAttributesTbl)')
+                        tr
+                            td.col-sm-12
+                                +table-pair-edit('stealingAttributesTbl', 'new', 'Attribute name', 'Attribute value', false, false, '{{::stealingAttributesTbl.focusId + $index}}', '-1', '=')

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/frontend/app/modules/states/configuration/clusters/collision/priority-queue.jade
----------------------------------------------------------------------
diff --git a/modules/web-console/frontend/app/modules/states/configuration/clusters/collision/priority-queue.jade b/modules/web-console/frontend/app/modules/states/configuration/clusters/collision/priority-queue.jade
new file mode 100644
index 0000000..bdd1dac
--- /dev/null
+++ b/modules/web-console/frontend/app/modules/states/configuration/clusters/collision/priority-queue.jade
@@ -0,0 +1,42 @@
+//-
+    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.jade
+
+-var model = 'backupItem.collision.PriorityQueue'
+
+div
+    .details-row
+        +number('Parallel jobs number:', model + '.parallelJobsNumber', '"priorityParallelJobsNumber"', 'true', 'availableProcessors * 2', '1',
+            'Number of jobs that can be executed in parallel')
+    .details-row
+        +number('Waiting jobs number:', model + '.waitingJobsNumber', '"priorityWaitingJobsNumber"', 'true', 'Integer.MAX_VALUE', '0',
+            'Maximum number of jobs that are allowed to wait in waiting queue')
+    .details-row
+        +text('Priority attribute key:', model + '.priorityAttributeKey', '"priorityPriorityAttributeKey"', 'false', 'grid.task.priority',
+            'Task priority attribute key')
+    .details-row
+        +text('Job priority attribute key:', model + '.jobPriorityAttributeKey', '"priorityJobPriorityAttributeKey"', 'false', 'grid.job.priority',
+            'Job priority attribute key')
+    .details-row
+        +number('Default priority:', model + '.defaultPriority', '"priorityDefaultPriority"', 'true', '0', '0',
+            'Default priority to use if a job does not have priority attribute set')
+    .details-row
+        +number('Starvation increment:', model + '.starvationIncrement', '"priorityStarvationIncrement"', 'true', '1', '0',
+            'Value to increment job priority by every time a lower priority job gets behind a higher priority job')
+    .details-row
+        +checkbox('Starvation prevention enabled', model + '.starvationPreventionEnabled', '"priorityStarvationPreventionEnabled"',
+            'Job starvation prevention is enabled')

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/frontend/app/modules/states/configuration/clusters/communication.jade
----------------------------------------------------------------------
diff --git a/modules/web-console/frontend/app/modules/states/configuration/clusters/communication.jade b/modules/web-console/frontend/app/modules/states/configuration/clusters/communication.jade
new file mode 100644
index 0000000..0643555
--- /dev/null
+++ b/modules/web-console/frontend/app/modules/states/configuration/clusters/communication.jade
@@ -0,0 +1,99 @@
+//-
+    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.jade
+
+-var form = 'communication'
+-var model = 'backupItem'
+-var communication = model + '.communication'
+
+.panel.panel-default(ng-form=form novalidate)
+    .panel-heading(bs-collapse-toggle ng-click='ui.loadPanel("#{form}")')
+        ignite-form-panel-chevron
+        label Communication
+        ignite-form-field-tooltip.tipLabel
+            | Configuration of communication with other nodes by TCP/IP
+            | Provide basic plumbing to send and receive grid messages and is utilized for all distributed grid operations
+        ignite-form-revert
+    .panel-collapse(role='tabpanel' bs-collapse-target id=form)
+        .panel-body(ng-if='ui.isPanelLoaded("#{form}")')
+            .col-sm-6
+                .settings-row
+                    +number('Timeout:', model + '.networkTimeout', '"commNetworkTimeout"', 'true', '5000', '1', 'Maximum timeout in milliseconds for network requests')
+                .settings-row
+                    +number('Send retry delay:', model + '.networkSendRetryDelay', '"networkSendRetryDelay"', 'true', '1000', '1', 'Interval in milliseconds between message send retries')
+                .settings-row
+                    +number('Send retry count:', model + '.networkSendRetryCount', '"networkSendRetryCount"', 'true', '3', '1', 'Message send retries count')
+                .settings-row
+                    +number('Discovery startup delay:', model + '.discoveryStartupDelay', '"discoveryStartupDelay"', 'true', '60000', '1', 'This value is used to expire messages from waiting list whenever node discovery discrepancies happen')
+                .settings-row
+                    +java-class('Communication listener:', communication + '.listener', '"comListener"', 'true', 'false', 'Listener of communication events')
+                .settings-row
+                    +text-ip-address('Local IP address:', communication + '.localAddress', '"comLocalAddress"', 'true', '0.0.0.0',
+                        'Local host address for socket binding<br/>\
+                        If not specified use all available addres on local host')
+                .settings-row
+                    +number-min-max('Local port:', communication + '.localPort', '"comLocalPort"', 'true', '47100', '1024', '65535', 'Local port for socket binding')
+                .settings-row
+                    +number('Local port range:', communication + '.localPortRange', '"comLocalPortRange"', 'true', '100', '1', 'Local port range for local host ports')
+                .settings-row
+                    +number-min-max('Shared memory port:', communication + '.sharedMemoryPort', '"sharedMemoryPort"', 'true', '48100', '-1', '65535',
+                        'Local port to accept shared memory connections<br/>\
+                        If set to #[b -1] shared memory communication will be disabled')
+                .settings-row
+                    +number('Idle connection timeout:', communication + '.idleConnectionTimeout', '"idleConnectionTimeout"', 'true', '30000', '1',
+                        'Maximum idle connection timeout upon which a connection to client will be closed')
+                .settings-row
+                    +number('Connect timeout:', communication + '.connectTimeout', '"connectTimeout"', 'true', '5000', '0', 'Connect timeout used when establishing connection with remote nodes')
+                .settings-row
+                    +number('Maximum connect timeout:', communication + '.maxConnectTimeout', '"maxConnectTimeout"', 'true', '600000', '0', 'Maximum connect timeout')
+                .settings-row
+                    +number('Reconnect count:', communication + '.reconnectCount', '"comReconnectCount"', 'true', '10', '1',
+                        'Maximum number of reconnect attempts used when establishing connection with remote nodes')
+                .settings-row
+                    +number('Socket send buffer:', communication + '.socketSendBuffer', '"socketSendBuffer"', 'true', '32768', '0', 'Send buffer size for sockets created or accepted by this SPI')
+                .settings-row
+                    +number('Socket receive buffer:', communication + '.socketReceiveBuffer', '"socketReceiveBuffer"', 'true', '32768', '0', 'Receive buffer size for sockets created or accepted by this SPI')
+                .settings-row
+                    +number('Slow client queue limit:', communication + '.slowClientQueueLimit', '"slowClientQueueLimit"', 'true', '0', '0', 'Slow client queue limit')
+                .settings-row
+                    +number('Ack send threshold:', communication + '.ackSendThreshold', '"ackSendThreshold"', 'true', '16', '1', 'Number of received messages per connection to node after which acknowledgment message is sent')
+                .settings-row
+                    +number('Message queue limit:', communication + '.messageQueueLimit', '"messageQueueLimit"', 'true', '1024', '0', 'Message queue limit for incoming and outgoing messages')
+                .settings-row
+                    +number('Unacknowledged messages:', communication + '.unacknowledgedMessagesBufferSize', '"unacknowledgedMessagesBufferSize"', 'true', '0', '0',
+                        'Maximum number of stored unacknowledged messages per connection to node<br/>\
+                        If specified non zero value it should be\
+                        <ul>\
+                            <li>At least ack send threshold * 5</li>\
+                            <li>At least message queue limit * 5</li>\
+                        </ul>')
+                .settings-row
+                    +number('Socket write timeout:', communication + '.socketWriteTimeout', '"socketWriteTimeout"', 'true', '2000', '0', 'Socket write timeout')
+                .settings-row
+                    +number('Selectors count:', communication + '.selectorsCount', '"selectorsCount"', 'true', 'min(4, availableProcessors)', '1', 'Count of selectors te be used in TCP server')
+                .settings-row
+                    +java-class('Address resolver:', communication + '.addressResolver', '"comAddressResolver"', 'true', 'false', 'Provides resolution between external and internal addresses')
+                .settings-row
+                    +checkbox('Direct buffer', communication + '.directBuffer', '"directBuffer"',
+                    'If value is true, then SPI will use ByteBuffer.allocateDirect(int) call<br/>\
+                    Otherwise, SPI will use ByteBuffer.allocate(int) call.')
+                .settings-row
+                    +checkbox('Direct send buffer', communication + '.directSendBuffer', '"directSendBuffer"', 'Flag defining whether direct send buffer should be used')
+                .settings-row
+                    +checkbox('TCP_NODELAY option', communication + '.tcpNoDelay', '"tcpNoDelay"', 'Value for TCP_NODELAY socket option')
+            .col-sm-6
+                +preview-xml-java(model, 'clusterCommunication')


[27/52] ignite git commit: Web Console beta-3.

Posted by ak...@apache.org.
http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/frontend/generator/generator-java.js
----------------------------------------------------------------------
diff --git a/modules/web-console/frontend/generator/generator-java.js b/modules/web-console/frontend/generator/generator-java.js
new file mode 100644
index 0000000..6cc3323
--- /dev/null
+++ b/modules/web-console/frontend/generator/generator-java.js
@@ -0,0 +1,3534 @@
+/*
+ * 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.
+ */
+
+// Java generation entry point.
+const $generatorJava = {};
+
+/**
+ * Translate some value to valid java code.
+ *
+ * @param val Value to convert.
+ * @param type Value type.
+ * @returns {*} String with value that will be valid for java.
+ */
+$generatorJava.toJavaCode = function(val, type) {
+    if (val === null)
+        return 'null';
+
+    if (type === 'raw')
+        return val;
+
+    if (type === 'class')
+        return val + '.class';
+
+    if (type === 'float')
+        return val + 'f';
+
+    if (type === 'path')
+        return '"' + val.replace(/\\/g, '\\\\') + '"';
+
+    if (type)
+        return type + '.' + val;
+
+    if (typeof (val) === 'string')
+        return '"' + val.replace('"', '\\"') + '"';
+
+    if (typeof (val) === 'number' || typeof (val) === 'boolean')
+        return String(val);
+
+    return 'Unknown type: ' + typeof (val) + ' (' + val + ')';
+};
+
+/**
+ * @param propName Property name.
+ * @param setterName Optional concrete setter name.
+ * @returns Property setter with name by java conventions.
+ */
+$generatorJava.setterName = function(propName, setterName) {
+    return setterName ? setterName : $generatorCommon.toJavaName('set', propName);
+};
+
+// Add constructor argument
+$generatorJava.constructorArg = function(obj, propName, dflt, notFirst, opt) {
+    const v = (obj ? obj[propName] : null) || dflt;
+
+    if ($generatorCommon.isDefinedAndNotEmpty(v))
+        return (notFirst ? ', ' : '') + $generatorJava.toJavaCode(v);
+    else if (!opt)
+        return notFirst ? ', null' : 'null';
+
+    return '';
+};
+
+/**
+ * Add variable declaration.
+ *
+ * @param res Resulting output with generated code.
+ * @param varName Variable name.
+ * @param varFullType Variable full class name to be added to imports.
+ * @param varFullActualType Variable actual full class name to be added to imports.
+ * @param varFullGenericType1 Optional full class name of first generic.
+ * @param varFullGenericType2 Optional full class name of second generic.
+ * @param subClass If 'true' then variable will be declared as anonymous subclass.
+ */
+$generatorJava.declareVariable = function(res, varName, varFullType, varFullActualType, varFullGenericType1, varFullGenericType2, subClass) {
+    res.emptyLineIfNeeded();
+
+    const varType = res.importClass(varFullType);
+
+    const varNew = !res.vars[varName];
+
+    if (varNew)
+        res.vars[varName] = true;
+
+    if (varFullActualType && varFullGenericType1) {
+        const varActualType = res.importClass(varFullActualType);
+        const varGenericType1 = res.importClass(varFullGenericType1);
+        let varGenericType2 = null;
+
+        if (varFullGenericType2)
+            varGenericType2 = res.importClass(varFullGenericType2);
+
+        res.line((varNew ? (varType + '<' + varGenericType1 + (varGenericType2 ? ', ' + varGenericType2 : '') + '> ') : '') +
+            varName + ' = new ' + varActualType + '<>();');
+    }
+    else
+        res.line((varNew ? (varType + ' ') : '') + varName + ' = new ' + varType + '()' + (subClass ? ' {' : ';'));
+
+    if (!subClass)
+        res.needEmptyLine = true;
+
+    return varName;
+};
+
+/**
+ * Add local variable declaration.
+ *
+ * @param res Resulting output with generated code.
+ * @param varName Variable name.
+ * @param varFullType Variable full class name to be added to imports.
+ */
+$generatorJava.declareVariableLocal = function(res, varName, varFullType) {
+    const varType = res.importClass(varFullType);
+
+    res.line(varType + ' ' + varName + ' = new ' + varType + '();');
+
+    res.needEmptyLine = true;
+};
+
+/**
+ * Add custom variable declaration.
+ *
+ * @param res Resulting output with generated code.
+ * @param varName Variable name.
+ * @param varFullType Variable full class name to be added to imports.
+ * @param varExpr Custom variable creation expression.
+ * @param modifier Additional variable modifier.
+ */
+$generatorJava.declareVariableCustom = function(res, varName, varFullType, varExpr, modifier) {
+    const varType = res.importClass(varFullType);
+
+    const varNew = !res.vars[varName];
+
+    if (varNew)
+        res.vars[varName] = true;
+
+    res.line((varNew ? ((modifier ? modifier + ' ' : '') + varType + ' ') : '') + varName + ' = ' + varExpr + ';');
+
+    res.needEmptyLine = true;
+};
+
+/**
+ * Add array variable declaration.
+ *
+ * @param res Resulting output with generated code.
+ * @param varName Variable name.
+ * @param varFullType Variable full class name to be added to imports.
+ * @param length Array length.
+ */
+$generatorJava.declareVariableArray = function(res, varName, varFullType, length) {
+    const varType = res.importClass(varFullType);
+
+    const varNew = !res.vars[varName];
+
+    if (varNew)
+        res.vars[varName] = true;
+
+    res.line((varNew ? (varType + '[] ') : '') + varName + ' = new ' + varType + '[' + length + '];');
+
+    res.needEmptyLine = true;
+};
+
+/**
+ * Clear list of declared variables.
+ *
+ * @param res
+ */
+$generatorJava.resetVariables = function(res) {
+    res.vars = {};
+};
+
+/**
+ * Add property via setter / property name.
+ *
+ * @param res Resulting output with generated code.
+ * @param varName Variable name.
+ * @param obj Source object with data.
+ * @param propName Property name to take from source object.
+ * @param dataType Optional info about property data type.
+ * @param setterName Optional special setter name.
+ * @param dflt Optional default value.
+ */
+$generatorJava.property = function(res, varName, obj, propName, dataType, setterName, dflt) {
+    if (!_.isNil(obj)) {
+        const val = obj[propName];
+
+        if ($generatorCommon.isDefinedAndNotEmpty(val)) {
+            const missDflt = _.isNil(dflt);
+
+            // Add to result if no default provided or value not equals to default.
+            if (missDflt || (!missDflt && val !== dflt)) {
+                res.line(varName + '.' + $generatorJava.setterName(propName, setterName) +
+                    '(' + $generatorJava.toJavaCode(val, dataType) + ');');
+
+                return true;
+            }
+        }
+    }
+
+    return false;
+};
+
+/**
+ * Add enum property via setter / property name.
+ *
+ * @param res Resulting output with generated code.
+ * @param varName Variable name.
+ * @param obj Source object with data.
+ * @param propName Property name to take from source object.
+ * @param dataType Name of enum class
+ * @param setterName Optional special setter name.
+ * @param dflt Optional default value.
+ */
+$generatorJava.enumProperty = function(res, varName, obj, propName, dataType, setterName, dflt) {
+    const val = obj[propName];
+
+    if ($generatorCommon.isDefinedAndNotEmpty(val)) {
+        const missDflt = _.isNil(dflt);
+
+        // Add to result if no default provided or value not equals to default.
+        if (missDflt || (!missDflt && val !== dflt)) {
+            res.line(varName + '.' + $generatorJava.setterName(propName, setterName) +
+                '(' + $generatorJava.toJavaCode(val, dataType ? res.importClass(dataType) : null) + ');');
+
+            return true;
+        }
+    }
+
+    return false;
+};
+
+// Add property for class name.
+$generatorJava.classNameProperty = function(res, varName, obj, propName) {
+    const val = obj[propName];
+
+    if (!_.isNil(val)) {
+        res.line(varName + '.' + $generatorJava.setterName(propName) +
+            '("' + $generatorCommon.JavaTypes.fullClassName(val) + '");');
+    }
+};
+
+/**
+ * Add list property.
+ *
+ * @param res Resulting output with generated code.
+ * @param varName Variable name.
+ * @param obj Source object with data.
+ * @param propName Property name to take from source object.
+ * @param dataType Optional data type.
+ * @param setterName Optional setter name.
+ */
+$generatorJava.listProperty = function(res, varName, obj, propName, dataType, setterName) {
+    const val = obj[propName];
+
+    if (val && val.length > 0) {
+        res.emptyLineIfNeeded();
+
+        res.importClass('java.util.Arrays');
+
+        $generatorJava.fxVarArgs(res, varName + '.' + $generatorJava.setterName(propName, setterName), false,
+            _.map(val, (v) => $generatorJava.toJavaCode(v, dataType)), '(Arrays.asList(', '))');
+
+        res.needEmptyLine = true;
+    }
+};
+
+/**
+ * Add function with varargs arguments.
+ *
+ * @param res Resulting output with generated code.
+ * @param fx Function name.
+ * @param quote Whether to quote arguments.
+ * @param args Array with arguments.
+ * @param startBlock Optional start block string.
+ * @param endBlock Optional end block string.
+ * @param startQuote Start quote string.
+ * @param endQuote End quote string.
+ */
+$generatorJava.fxVarArgs = function(res, fx, quote, args, startBlock = '(', endBlock = ')', startQuote = '"', endQuote = '"') {
+    const quoteArg = (arg) => quote ? startQuote + arg + endQuote : arg;
+
+    if (args.length === 1)
+        res.append(fx + startBlock + quoteArg(args[0]) + endBlock + ';');
+    else {
+        res.startBlock(fx + startBlock);
+
+        const len = args.length - 1;
+
+        _.forEach(args, (arg, ix) => res.line(quoteArg(arg) + (ix < len ? ', ' : '')));
+
+        res.endBlock(endBlock + ';');
+    }
+};
+
+/**
+ * Add array property.
+ *
+ * @param res Resulting output with generated code.
+ * @param varName Variable name.
+ * @param obj Source object with data.
+ * @param propName Property name to take from source object.
+ * @param setterName Optional setter name.
+ */
+$generatorJava.arrayProperty = function(res, varName, obj, propName, setterName) {
+    const val = obj[propName];
+
+    if (val && val.length > 0) {
+        res.emptyLineIfNeeded();
+
+        $generatorJava.fxVarArgs(res, varName + '.' + $generatorJava.setterName(propName, setterName), false,
+            _.map(val, (v) => 'new ' + res.importClass(v) + '()'), '({ ', ' });');
+
+        res.needEmptyLine = true;
+    }
+};
+
+/**
+ * Add multi-param property (setter with several arguments).
+ *
+ * @param res Resulting output with generated code.
+ * @param varName Variable name.
+ * @param obj Source object with data.
+ * @param propName Property name to take from source object.
+ * @param dataType Optional data type.
+ * @param setterName Optional setter name.
+ */
+$generatorJava.multiparamProperty = function(res, varName, obj, propName, dataType, setterName) {
+    const val = obj[propName];
+
+    if (val && val.length > 0) {
+        $generatorJava.fxVarArgs(res, varName + '.' + $generatorJava.setterName(propName, setterName), false,
+            _.map(val, (v) => $generatorJava.toJavaCode(dataType === 'class' ? res.importClass(v) : v, dataType)));
+    }
+};
+
+/**
+ * Add complex bean.
+ *
+ * @param res Resulting output with generated code.
+ * @param varName Variable name.
+ * @param bean
+ * @param beanPropName Bean property name.
+ * @param beanVarName
+ * @param beanClass Bean class.
+ * @param props
+ * @param createBeanAlthoughNoProps If 'true' then create empty bean.
+ */
+$generatorJava.beanProperty = function(res, varName, bean, beanPropName, beanVarName, beanClass, props, createBeanAlthoughNoProps) {
+    if (bean && $generatorCommon.hasProperty(bean, props)) {
+        res.emptyLineIfNeeded();
+
+        $generatorJava.declareVariable(res, beanVarName, beanClass);
+
+        _.forIn(props, function(descr, propName) {
+            if (props.hasOwnProperty(propName)) {
+                if (descr) {
+                    switch (descr.type) {
+                        case 'list':
+                            $generatorJava.listProperty(res, beanVarName, bean, propName, descr.elementsType, descr.setterName);
+                            break;
+
+                        case 'array':
+                            $generatorJava.arrayProperty(res, beanVarName, bean, propName, descr.setterName);
+                            break;
+
+                        case 'enum':
+                            $generatorJava.enumProperty(res, beanVarName, bean, propName, descr.enumClass, descr.setterName, descr.dflt);
+                            break;
+
+                        case 'float':
+                            $generatorJava.property(res, beanVarName, bean, propName, 'float', descr.setterName);
+                            break;
+
+                        case 'path':
+                            $generatorJava.property(res, beanVarName, bean, propName, 'path', descr.setterName);
+                            break;
+
+                        case 'raw':
+                            $generatorJava.property(res, beanVarName, bean, propName, 'raw', descr.setterName);
+                            break;
+
+                        case 'propertiesAsList':
+                            const val = bean[propName];
+
+                            if (val && val.length > 0) {
+                                $generatorJava.declareVariable(res, descr.propVarName, 'java.util.Properties');
+
+                                _.forEach(val, function(nameAndValue) {
+                                    const eqIndex = nameAndValue.indexOf('=');
+
+                                    if (eqIndex >= 0) {
+                                        res.line(descr.propVarName + '.setProperty(' +
+                                            '"' + nameAndValue.substring(0, eqIndex) + '", ' +
+                                            '"' + nameAndValue.substr(eqIndex + 1) + '");');
+                                    }
+                                });
+
+                                res.needEmptyLine = true;
+
+                                res.line(beanVarName + '.' + $generatorJava.setterName(propName) + '(' + descr.propVarName + ');');
+                            }
+                            break;
+
+                        case 'bean':
+                            if ($generatorCommon.isDefinedAndNotEmpty(bean[propName]))
+                                res.line(beanVarName + '.' + $generatorJava.setterName(propName) + '(new ' + res.importClass(bean[propName]) + '());');
+
+                            break;
+
+                        default:
+                            $generatorJava.property(res, beanVarName, bean, propName, null, descr.setterName, descr.dflt);
+                    }
+                }
+                else
+                    $generatorJava.property(res, beanVarName, bean, propName);
+            }
+        });
+
+        res.needEmptyLine = true;
+
+        res.line(varName + '.' + $generatorJava.setterName(beanPropName) + '(' + beanVarName + ');');
+
+        res.needEmptyLine = true;
+    }
+    else if (createBeanAlthoughNoProps) {
+        res.emptyLineIfNeeded();
+        res.line(varName + '.' + $generatorJava.setterName(beanPropName) + '(new ' + res.importClass(beanClass) + '());');
+
+        res.needEmptyLine = true;
+    }
+};
+
+/**
+ * Add eviction policy.
+ *
+ * @param res Resulting output with generated code.
+ * @param varName Current using variable name.
+ * @param evtPlc Data to add.
+ * @param propName Name in source data.
+ */
+$generatorJava.evictionPolicy = function(res, varName, evtPlc, propName) {
+    if (evtPlc && evtPlc.kind) {
+        const evictionPolicyDesc = $generatorCommon.EVICTION_POLICIES[evtPlc.kind];
+
+        const obj = evtPlc[evtPlc.kind.toUpperCase()];
+
+        $generatorJava.beanProperty(res, varName, obj, propName, propName,
+            evictionPolicyDesc.className, evictionPolicyDesc.fields, true);
+    }
+};
+
+// Generate cluster general group.
+$generatorJava.clusterGeneral = function(cluster, clientNearCfg, res) {
+    if (!res)
+        res = $generatorCommon.builder();
+
+    $generatorJava.declareVariable(res, 'cfg', 'org.apache.ignite.configuration.IgniteConfiguration');
+
+    $generatorJava.property(res, 'cfg', cluster, 'name', null, 'setGridName');
+    res.needEmptyLine = true;
+
+    $generatorJava.property(res, 'cfg', cluster, 'localHost');
+    res.needEmptyLine = true;
+
+    if (clientNearCfg) {
+        res.line('cfg.setClientMode(true);');
+
+        res.needEmptyLine = true;
+    }
+
+    if (cluster.discovery) {
+        const d = cluster.discovery;
+
+        $generatorJava.declareVariable(res, 'discovery', 'org.apache.ignite.spi.discovery.tcp.TcpDiscoverySpi');
+
+        switch (d.kind) {
+            case 'Multicast':
+                $generatorJava.beanProperty(res, 'discovery', d.Multicast, 'ipFinder', 'ipFinder',
+                    'org.apache.ignite.spi.discovery.tcp.ipfinder.multicast.TcpDiscoveryMulticastIpFinder',
+                    {
+                        multicastGroup: null,
+                        multicastPort: null,
+                        responseWaitTime: null,
+                        addressRequestAttempts: null,
+                        localAddress: null,
+                        addresses: {type: 'list'}
+                    }, true);
+
+                break;
+
+            case 'Vm':
+                $generatorJava.beanProperty(res, 'discovery', d.Vm, 'ipFinder', 'ipFinder',
+                    'org.apache.ignite.spi.discovery.tcp.ipfinder.vm.TcpDiscoveryVmIpFinder',
+                    {addresses: {type: 'list'}}, true);
+
+                break;
+
+            case 'S3':
+                $generatorJava.beanProperty(res, 'discovery', d.S3, 'ipFinder', 'ipFinder',
+                    'org.apache.ignite.spi.discovery.tcp.ipfinder.s3.TcpDiscoveryS3IpFinder', {bucketName: null}, true);
+
+                break;
+
+            case 'Cloud':
+                $generatorJava.beanProperty(res, 'discovery', d.Cloud, 'ipFinder', 'ipFinder',
+                    'org.apache.ignite.spi.discovery.tcp.ipfinder.cloud.TcpDiscoveryCloudIpFinder',
+                    {
+                        credential: null,
+                        credentialPath: null,
+                        identity: null,
+                        provider: null,
+                        regions: {type: 'list'},
+                        zones: {type: 'list'}
+                    }, true);
+
+                break;
+
+            case 'GoogleStorage':
+                $generatorJava.beanProperty(res, 'discovery', d.GoogleStorage, 'ipFinder', 'ipFinder',
+                    'org.apache.ignite.spi.discovery.tcp.ipfinder.gce.TcpDiscoveryGoogleStorageIpFinder',
+                    {
+                        projectName: null,
+                        bucketName: null,
+                        serviceAccountP12FilePath: null,
+                        serviceAccountId: null
+                    }, true);
+
+                break;
+
+            case 'Jdbc':
+                $generatorJava.declareVariable(res, 'ipFinder',
+                    'org.apache.ignite.spi.discovery.tcp.ipfinder.jdbc.TcpDiscoveryJdbcIpFinder');
+                $generatorJava.property(res, 'ipFinder', d.Jdbc, 'initSchema');
+
+                const datasource = d.Jdbc;
+                if (datasource.dataSourceBean && datasource.dialect) {
+                    res.needEmptyLine = !datasource.initSchema;
+
+                    res.line('ipFinder.setDataSource(DataSources.INSTANCE_' + datasource.dataSourceBean + ');');
+                }
+
+                res.needEmptyLine = true;
+
+                res.line('discovery.setIpFinder(ipFinder);');
+
+                break;
+
+            case 'SharedFs':
+                $generatorJava.beanProperty(res, 'discovery', d.SharedFs, 'ipFinder', 'ipFinder',
+                    'org.apache.ignite.spi.discovery.tcp.ipfinder.sharedfs.TcpDiscoverySharedFsIpFinder', {path: null}, true);
+
+                break;
+
+            case 'ZooKeeper':
+                const finderVar = 'ipFinder';
+
+                $generatorJava.declareVariable(res, 'ipFinder', 'org.apache.ignite.spi.discovery.tcp.ipfinder.zk.TcpDiscoveryZookeeperIpFinder');
+
+                if (d.ZooKeeper) {
+                    if ($generatorCommon.isDefinedAndNotEmpty(d.ZooKeeper.curator))
+                        res.line(finderVar + '.setCurator(new ' + res.importClass(d.ZooKeeper.curator) + '());');
+
+                    $generatorJava.property(res, finderVar, d.ZooKeeper, 'zkConnectionString');
+
+                    if (d.ZooKeeper.retryPolicy && d.ZooKeeper.retryPolicy.kind) {
+                        const kind = d.ZooKeeper.retryPolicy.kind;
+                        const retryPolicy = d.ZooKeeper.retryPolicy[kind];
+
+                        switch (kind) {
+                            case 'ExponentialBackoff':
+                                res.line(finderVar + '.setRetryPolicy(new ' + res.importClass('org.apache.curator.retry.ExponentialBackoffRetry') + '(' +
+                                    $generatorJava.constructorArg(retryPolicy, 'baseSleepTimeMs', 1000) +
+                                    $generatorJava.constructorArg(retryPolicy, 'maxRetries', 10, true) +
+                                    $generatorJava.constructorArg(retryPolicy, 'maxSleepMs', null, true, true) + '));');
+
+                                break;
+
+                            case 'BoundedExponentialBackoff':
+                                res.line(finderVar + '.setRetryPolicy(new ' + res.importClass('org.apache.curator.retry.BoundedExponentialBackoffRetry') + '(' +
+                                    $generatorJava.constructorArg(retryPolicy, 'baseSleepTimeMs', 1000) +
+                                    $generatorJava.constructorArg(retryPolicy, 'maxSleepTimeMs', 2147483647, true) +
+                                    $generatorJava.constructorArg(retryPolicy, 'maxRetries', 10, true) + '));');
+
+                                break;
+
+                            case 'UntilElapsed':
+                                res.line(finderVar + '.setRetryPolicy(new ' + res.importClass('org.apache.curator.retry.RetryUntilElapsed') + '(' +
+                                    $generatorJava.constructorArg(retryPolicy, 'maxElapsedTimeMs', 60000) +
+                                    $generatorJava.constructorArg(retryPolicy, 'sleepMsBetweenRetries', 1000, true) + '));');
+
+                                break;
+
+                            case 'NTimes':
+                                res.line(finderVar + '.setRetryPolicy(new ' + res.importClass('org.apache.curator.retry.RetryNTimes') + '(' +
+                                    $generatorJava.constructorArg(retryPolicy, 'n', 10) +
+                                    $generatorJava.constructorArg(retryPolicy, 'sleepMsBetweenRetries', 1000, true) + '));');
+
+                                break;
+
+                            case 'OneTime':
+                                res.line(finderVar + '.setRetryPolicy(new ' + res.importClass('org.apache.curator.retry.RetryOneTime') + '(' +
+                                    $generatorJava.constructorArg(retryPolicy, 'sleepMsBetweenRetry', 1000) + '));');
+
+                                break;
+
+                            case 'Forever':
+                                res.line(finderVar + '.setRetryPolicy(new ' + res.importClass('org.apache.curator.retry.RetryForever') + '(' +
+                                    $generatorJava.constructorArg(retryPolicy, 'retryIntervalMs', 1000) + '));');
+
+                                break;
+
+                            case 'Custom':
+                                if (retryPolicy && $generatorCommon.isDefinedAndNotEmpty(retryPolicy.className))
+                                    res.line(finderVar + '.setRetryPolicy(new ' + res.importClass(retryPolicy.className) + '());');
+
+                                break;
+
+                            default:
+                        }
+                    }
+
+                    $generatorJava.property(res, finderVar, d.ZooKeeper, 'basePath', null, null, '/services');
+                    $generatorJava.property(res, finderVar, d.ZooKeeper, 'serviceName', null, null, 'ignite');
+                    $generatorJava.property(res, finderVar, d.ZooKeeper, 'allowDuplicateRegistrations', null, null, false);
+                }
+
+                res.line('discovery.setIpFinder(ipFinder);');
+
+                break;
+
+            default:
+                res.line('Unknown discovery kind: ' + d.kind);
+        }
+
+        res.needEmptyLine = false;
+
+        $generatorJava.clusterDiscovery(d, res);
+
+        res.emptyLineIfNeeded();
+
+        res.line('cfg.setDiscoverySpi(discovery);');
+
+        res.needEmptyLine = true;
+    }
+
+    return res;
+};
+
+// Generate atomics group.
+$generatorJava.clusterAtomics = function(atomics, res) {
+    if (!res)
+        res = $generatorCommon.builder();
+
+    if ($generatorCommon.hasAtLeastOneProperty(atomics, ['cacheMode', 'atomicSequenceReserveSize', 'backups'])) {
+        res.startSafeBlock();
+
+        $generatorJava.declareVariable(res, 'atomicCfg', 'org.apache.ignite.configuration.AtomicConfiguration');
+
+        $generatorJava.enumProperty(res, 'atomicCfg', atomics, 'cacheMode', 'org.apache.ignite.cache.CacheMode', null, 'PARTITIONED');
+
+        const cacheMode = atomics.cacheMode ? atomics.cacheMode : 'PARTITIONED';
+
+        let hasData = cacheMode !== 'PARTITIONED';
+
+        hasData = $generatorJava.property(res, 'atomicCfg', atomics, 'atomicSequenceReserveSize', null, null, 1000) || hasData;
+
+        if (cacheMode === 'PARTITIONED')
+            hasData = $generatorJava.property(res, 'atomicCfg', atomics, 'backups', null, null, 0) || hasData;
+
+        res.needEmptyLine = true;
+
+        res.line('cfg.setAtomicConfiguration(atomicCfg);');
+
+        res.needEmptyLine = true;
+
+        if (!hasData)
+            res.rollbackSafeBlock();
+    }
+
+    return res;
+};
+
+// Generate binary group.
+$generatorJava.clusterBinary = function(binary, res) {
+    if (!res)
+        res = $generatorCommon.builder();
+
+    if ($generatorCommon.binaryIsDefined(binary)) {
+        const varName = 'binary';
+
+        $generatorJava.declareVariable(res, varName, 'org.apache.ignite.configuration.BinaryConfiguration');
+
+        if ($generatorCommon.isDefinedAndNotEmpty(binary.idMapper))
+            res.line(varName + '.setIdMapper(new ' + res.importClass(binary.idMapper) + '());');
+
+        if ($generatorCommon.isDefinedAndNotEmpty(binary.nameMapper))
+            res.line(varName + '.setNameMapper(new ' + res.importClass(binary.nameMapper) + '());');
+
+        if ($generatorCommon.isDefinedAndNotEmpty(binary.serializer))
+            res.line(varName + '.setSerializer(new ' + res.importClass(binary.serializer) + '());');
+
+        res.needEmptyLine = $generatorCommon.isDefinedAndNotEmpty(binary.idMapper) || $generatorCommon.isDefinedAndNotEmpty(binary.serializer);
+
+        if ($generatorCommon.isDefinedAndNotEmpty(binary.typeConfigurations)) {
+            const arrVar = 'types';
+
+            $generatorJava.declareVariable(res, arrVar, 'java.util.Collection', 'java.util.ArrayList', 'org.apache.ignite.binary.BinaryTypeConfiguration');
+
+            _.forEach(binary.typeConfigurations, function(type) {
+                if ($generatorCommon.isDefinedAndNotEmpty(type.typeName))
+                    res.line(arrVar + '.add(' + $generatorJava.binaryTypeFunctionName(type.typeName) + '());'); // TODO IGNITE-2269 Replace using of separated methods for binary type configurations to extended constructors.
+            });
+
+            res.needEmptyLine = true;
+
+            res.line(varName + '.setTypeConfigurations(' + arrVar + ');');
+
+            res.needEmptyLine = true;
+        }
+
+        $generatorJava.property(res, varName, binary, 'compactFooter', null, null, true);
+
+        res.needEmptyLine = true;
+
+        res.line('cfg.setBinaryConfiguration(' + varName + ');');
+
+        res.needEmptyLine = true;
+    }
+
+    return res;
+};
+
+// Generate cache key configurations.
+$generatorJava.clusterCacheKeyConfiguration = function(keyCfgs, res) {
+    if (!res)
+        res = $generatorCommon.builder();
+
+    keyCfgs = _.filter(keyCfgs, (cfg) => cfg.typeName && cfg.affinityKeyFieldName);
+
+    if (_.isEmpty(keyCfgs))
+        return res;
+
+    $generatorJava.declareVariableArray(res, 'keyConfigurations', 'org.apache.ignite.cache.CacheKeyConfiguration', keyCfgs.length);
+
+    const cacheKeyCfg = res.importClass('org.apache.ignite.cache.CacheKeyConfiguration');
+
+    _.forEach(keyCfgs, (cfg, idx) => {
+        res.needEmptyLine = true;
+
+        res.line(`keyConfigurations[${idx}] = new ${cacheKeyCfg}("${cfg.typeName}", "${cfg.affinityKeyFieldName}");`);
+
+        res.needEmptyLine = true;
+    });
+
+    res.line('cfg.setCacheKeyConfiguration(keyConfigurations);');
+
+    res.needEmptyLine = true;
+
+    return res;
+};
+
+// TODO IGNITE-2269 Remove specified methods after implamentation of extended constructors.
+// Construct binary type configuration factory method name.
+$generatorJava.binaryTypeFunctionName = function(typeName) {
+    const dotIdx = typeName.lastIndexOf('.');
+
+    const shortName = dotIdx > 0 ? typeName.substr(dotIdx + 1) : typeName;
+
+    return $generatorCommon.toJavaName('binaryType', shortName);
+};
+
+// TODO IGNITE-2269 Remove specified methods after implamentation of extended constructors.
+// Generate factory method for specified BinaryTypeConfiguration.
+$generatorJava.binaryTypeConfiguration = function(type, res) {
+    const typeName = type.typeName;
+
+    res.line('/**');
+    res.line(' * Create binary type configuration for ' + typeName + '.');
+    res.line(' *');
+    res.line(' * @return Configured binary type.');
+    res.line(' */');
+    res.startBlock('private static BinaryTypeConfiguration ' + $generatorJava.binaryTypeFunctionName(typeName) + '() {');
+
+    $generatorJava.resetVariables(res);
+
+    const typeVar = 'typeCfg';
+
+    $generatorJava.declareVariable(res, typeVar, 'org.apache.ignite.binary.BinaryTypeConfiguration');
+
+    $generatorJava.property(res, typeVar, type, 'typeName');
+
+    if ($generatorCommon.isDefinedAndNotEmpty(type.idMapper))
+        res.line(typeVar + '.setIdMapper(new ' + res.importClass(type.idMapper) + '());');
+
+    if ($generatorCommon.isDefinedAndNotEmpty(type.nameMapper))
+        res.line(typeVar + '.setNameMapper(new ' + res.importClass(type.nameMapper) + '());');
+
+    if ($generatorCommon.isDefinedAndNotEmpty(type.serializer))
+        res.line(typeVar + '.setSerializer(new ' + res.importClass(type.serializer) + '());');
+
+    $generatorJava.property(res, typeVar, type, 'enum', null, null, false);
+
+    res.needEmptyLine = true;
+
+    res.line('return ' + typeVar + ';');
+    res.endBlock('}');
+
+    res.needEmptyLine = true;
+};
+
+// TODO IGNITE-2269 Remove specified methods after implamentation of extended constructors.
+// Generates binary type configuration factory methods.
+$generatorJava.binaryTypeConfigurations = function(binary, res) {
+    if (!res)
+        res = $generatorCommon.builder();
+
+    if (!_.isNil(binary)) {
+        _.forEach(binary.typeConfigurations, function(type) {
+            $generatorJava.binaryTypeConfiguration(type, res);
+        });
+    }
+
+    return res;
+};
+
+// Generate collision group.
+$generatorJava.clusterCollision = function(collision, res) {
+    if (!res)
+        res = $generatorCommon.builder();
+
+    if (collision && collision.kind && collision.kind !== 'Noop') {
+        const spi = collision[collision.kind];
+
+        if (collision.kind !== 'Custom' || (spi && $generatorCommon.isDefinedAndNotEmpty(spi.class))) {
+            const varName = 'collisionSpi';
+
+            switch (collision.kind) {
+                case 'JobStealing':
+                    $generatorJava.declareVariable(res, varName, 'org.apache.ignite.spi.collision.jobstealing.JobStealingCollisionSpi');
+
+                    $generatorJava.property(res, varName, spi, 'activeJobsThreshold', null, null, 95);
+                    $generatorJava.property(res, varName, spi, 'waitJobsThreshold', null, null, 0);
+                    $generatorJava.property(res, varName, spi, 'messageExpireTime', null, null, 1000);
+                    $generatorJava.property(res, varName, spi, 'maximumStealingAttempts', null, null, 5);
+                    $generatorJava.property(res, varName, spi, 'stealingEnabled', null, null, true);
+
+                    if ($generatorCommon.isDefinedAndNotEmpty(spi.externalCollisionListener)) {
+                        res.line(varName + '.' + $generatorJava.setterName('externalCollisionListener') +
+                            '(new ' + res.importClass(spi.externalCollisionListener) + '());');
+                    }
+
+                    if ($generatorCommon.isDefinedAndNotEmpty(spi.stealingAttributes)) {
+                        const stealingAttrsVar = 'stealingAttrs';
+
+                        res.needEmptyLine = true;
+
+                        $generatorJava.declareVariable(res, stealingAttrsVar, 'java.util.Map', 'java.util.HashMap', 'String', 'java.io.Serializable');
+
+                        _.forEach(spi.stealingAttributes, function(attr) {
+                            res.line(stealingAttrsVar + '.put("' + attr.name + '", "' + attr.value + '");');
+                        });
+
+                        res.needEmptyLine = true;
+
+                        res.line(varName + '.setStealingAttributes(' + stealingAttrsVar + ');');
+                    }
+
+                    break;
+
+                case 'FifoQueue':
+                    $generatorJava.declareVariable(res, varName, 'org.apache.ignite.spi.collision.fifoqueue.FifoQueueCollisionSpi');
+
+                    $generatorJava.property(res, varName, spi, 'parallelJobsNumber');
+                    $generatorJava.property(res, varName, spi, 'waitingJobsNumber');
+
+                    break;
+
+                case 'PriorityQueue':
+                    $generatorJava.declareVariable(res, varName, 'org.apache.ignite.spi.collision.priorityqueue.PriorityQueueCollisionSpi');
+
+                    $generatorJava.property(res, varName, spi, 'parallelJobsNumber');
+                    $generatorJava.property(res, varName, spi, 'waitingJobsNumber');
+                    $generatorJava.property(res, varName, spi, 'priorityAttributeKey', null, null, 'grid.task.priority');
+                    $generatorJava.property(res, varName, spi, 'jobPriorityAttributeKey', null, null, 'grid.job.priority');
+                    $generatorJava.property(res, varName, spi, 'defaultPriority', null, null, 0);
+                    $generatorJava.property(res, varName, spi, 'starvationIncrement', null, null, 1);
+                    $generatorJava.property(res, varName, spi, 'starvationPreventionEnabled', null, null, true);
+
+                    break;
+
+                case 'Custom':
+                    $generatorJava.declareVariable(res, varName, spi.class);
+
+                    break;
+
+                default:
+            }
+
+            res.needEmptyLine = true;
+
+            res.line('cfg.setCollisionSpi(' + varName + ');');
+
+            res.needEmptyLine = true;
+        }
+    }
+
+    return res;
+};
+
+// Generate communication group.
+$generatorJava.clusterCommunication = function(cluster, res) {
+    if (!res)
+        res = $generatorCommon.builder();
+
+    const cfg = $generatorCommon.COMMUNICATION_CONFIGURATION;
+
+    $generatorJava.beanProperty(res, 'cfg', cluster.communication, 'communicationSpi', 'commSpi', cfg.className, cfg.fields);
+
+    res.needEmptyLine = false;
+
+    $generatorJava.property(res, 'cfg', cluster, 'networkTimeout', null, null, 5000);
+    $generatorJava.property(res, 'cfg', cluster, 'networkSendRetryDelay', null, null, 1000);
+    $generatorJava.property(res, 'cfg', cluster, 'networkSendRetryCount', null, null, 3);
+    $generatorJava.property(res, 'cfg', cluster, 'segmentCheckFrequency');
+    $generatorJava.property(res, 'cfg', cluster, 'waitForSegmentOnStart', null, null, false);
+    $generatorJava.property(res, 'cfg', cluster, 'discoveryStartupDelay', null, null, 60000);
+
+    res.needEmptyLine = true;
+
+    return res;
+};
+
+// Generate REST access group.
+$generatorJava.clusterConnector = function(connector, res) {
+    if (!res)
+        res = $generatorCommon.builder();
+
+    if (!_.isNil(connector) && connector.enabled) {
+        const cfg = _.cloneDeep($generatorCommon.CONNECTOR_CONFIGURATION);
+
+        if (connector.sslEnabled) {
+            cfg.fields.sslClientAuth = {dflt: false};
+            cfg.fields.sslFactory = {type: 'bean'};
+        }
+
+        $generatorJava.beanProperty(res, 'cfg', connector, 'connectorConfiguration', 'clientCfg',
+            cfg.className, cfg.fields, true);
+
+        res.needEmptyLine = true;
+    }
+
+    return res;
+};
+
+// Generate deployment group.
+$generatorJava.clusterDeployment = function(cluster, res) {
+    if (!res)
+        res = $generatorCommon.builder();
+
+    $generatorJava.enumProperty(res, 'cfg', cluster, 'deploymentMode', 'org.apache.ignite.configuration.DeploymentMode', null, 'SHARED');
+
+    res.softEmptyLine();
+
+    const p2pEnabled = cluster.peerClassLoadingEnabled;
+
+    if (!_.isNil(p2pEnabled)) {
+        $generatorJava.property(res, 'cfg', cluster, 'peerClassLoadingEnabled', null, null, false);
+
+        if (p2pEnabled) {
+            $generatorJava.property(res, 'cfg', cluster, 'peerClassLoadingMissedResourcesCacheSize', null, null, 100);
+            $generatorJava.property(res, 'cfg', cluster, 'peerClassLoadingThreadPoolSize', null, null, 2);
+            $generatorJava.multiparamProperty(res, 'cfg', cluster, 'peerClassLoadingLocalClassPathExclude');
+        }
+
+        res.needEmptyLine = true;
+    }
+
+    return res;
+};
+
+// Generate discovery group.
+$generatorJava.clusterDiscovery = function(disco, res) {
+    if (!res)
+        res = $generatorCommon.builder();
+
+    if (disco) {
+        $generatorJava.property(res, 'discovery', disco, 'localAddress');
+        $generatorJava.property(res, 'discovery', disco, 'localPort', null, null, 47500);
+        $generatorJava.property(res, 'discovery', disco, 'localPortRange', null, null, 100);
+
+        if ($generatorCommon.isDefinedAndNotEmpty(disco.addressResolver)) {
+            $generatorJava.beanProperty(res, 'discovery', disco, 'addressResolver', 'addressResolver', disco.addressResolver, {}, true);
+            res.needEmptyLine = false;
+        }
+
+        $generatorJava.property(res, 'discovery', disco, 'socketTimeout', null, null, 5000);
+        $generatorJava.property(res, 'discovery', disco, 'ackTimeout', null, null, 5000);
+        $generatorJava.property(res, 'discovery', disco, 'maxAckTimeout', null, null, 600000);
+        $generatorJava.property(res, 'discovery', disco, 'networkTimeout', null, null, 5000);
+        $generatorJava.property(res, 'discovery', disco, 'joinTimeout', null, null, 0);
+        $generatorJava.property(res, 'discovery', disco, 'threadPriority', null, null, 10);
+        $generatorJava.property(res, 'discovery', disco, 'heartbeatFrequency', null, null, 2000);
+        $generatorJava.property(res, 'discovery', disco, 'maxMissedHeartbeats', null, null, 1);
+        $generatorJava.property(res, 'discovery', disco, 'maxMissedClientHeartbeats', null, null, 5);
+        $generatorJava.property(res, 'discovery', disco, 'topHistorySize', null, null, 1000);
+
+        if ($generatorCommon.isDefinedAndNotEmpty(disco.listener)) {
+            $generatorJava.beanProperty(res, 'discovery', disco, 'listener', 'listener', disco.listener, {}, true);
+            res.needEmptyLine = false;
+        }
+
+        if ($generatorCommon.isDefinedAndNotEmpty(disco.dataExchange)) {
+            $generatorJava.beanProperty(res, 'discovery', disco, 'dataExchange', 'dataExchange', disco.dataExchange, {}, true);
+            res.needEmptyLine = false;
+        }
+
+        if ($generatorCommon.isDefinedAndNotEmpty(disco.metricsProvider)) {
+            $generatorJava.beanProperty(res, 'discovery', disco, 'metricsProvider', 'metricsProvider', disco.metricsProvider, {}, true);
+            res.needEmptyLine = false;
+        }
+
+        $generatorJava.property(res, 'discovery', disco, 'reconnectCount', null, null, 10);
+        $generatorJava.property(res, 'discovery', disco, 'statisticsPrintFrequency', null, null, 0);
+        $generatorJava.property(res, 'discovery', disco, 'ipFinderCleanFrequency', null, null, 60000);
+
+        if ($generatorCommon.isDefinedAndNotEmpty(disco.authenticator)) {
+            $generatorJava.beanProperty(res, 'discovery', disco, 'authenticator', 'authenticator', disco.authenticator, {}, true);
+            res.needEmptyLine = false;
+        }
+
+        $generatorJava.property(res, 'discovery', disco, 'forceServerMode', null, null, false);
+        $generatorJava.property(res, 'discovery', disco, 'clientReconnectDisabled', null, null, false);
+
+        res.needEmptyLine = true;
+    }
+
+    return res;
+};
+
+// Generate events group.
+$generatorJava.clusterEvents = function(cluster, res) {
+    if (!res)
+        res = $generatorCommon.builder();
+
+    if (cluster.includeEventTypes && cluster.includeEventTypes.length > 0) {
+        res.emptyLineIfNeeded();
+
+        const evtGrps = angular.element(document.getElementById('app')).injector().get('igniteEventGroups');
+
+        if (cluster.includeEventTypes.length === 1) {
+            const evtGrp = _.find(evtGrps, {value: cluster.includeEventTypes[0]});
+            const evts = res.importStatic(evtGrp.class + '.' + evtGrp.value);
+
+            res.line('cfg.setIncludeEventTypes(' + evts + ');');
+        }
+        else {
+            _.forEach(cluster.includeEventTypes, function(value, ix) {
+                const evtGrp = _.find(evtGrps, {value});
+                const evts = res.importStatic(evtGrp.class + '.' + evtGrp.value);
+
+                if (ix === 0)
+                    res.line('int[] events = new int[' + evts + '.length');
+                else
+                    res.line('    + ' + evts + '.length');
+            });
+
+            res.line('];');
+
+            res.needEmptyLine = true;
+
+            res.line('int k = 0;');
+
+            _.forEach(cluster.includeEventTypes, function(value, idx) {
+                res.needEmptyLine = true;
+
+                const evtGrp = _.find(evtGrps, {value});
+                const evts = res.importStatic(evtGrp.class + '.' + value);
+
+                res.line('System.arraycopy(' + evts + ', 0, events, k, ' + evts + '.length);');
+
+                if (idx < cluster.includeEventTypes.length - 1)
+                    res.line('k += ' + evts + '.length;');
+            });
+
+            res.needEmptyLine = true;
+
+            res.line('cfg.setIncludeEventTypes(events);');
+        }
+
+        res.needEmptyLine = true;
+    }
+
+    res.needEmptyLine = true;
+
+    return res;
+};
+
+// Generate failover group.
+$generatorJava.clusterFailover = function(cluster, res) {
+    if (!res)
+        res = $generatorCommon.builder();
+
+    if ($generatorCommon.isDefinedAndNotEmpty(cluster.failoverSpi) && _.findIndex(cluster.failoverSpi, function(spi) {
+        return $generatorCommon.isDefinedAndNotEmpty(spi.kind) && (spi.kind !== 'Custom' || $generatorCommon.isDefinedAndNotEmpty(_.get(spi, spi.kind + '.class')));
+    }) >= 0) {
+        const arrayVarName = 'failoverSpiList';
+
+        $generatorJava.declareVariable(res, arrayVarName, 'java.util.List', 'java.util.ArrayList', 'org.apache.ignite.spi.failover.FailoverSpi');
+
+        _.forEach(cluster.failoverSpi, function(spi) {
+            if (spi.kind && (spi.kind !== 'Custom' || $generatorCommon.isDefinedAndNotEmpty(_.get(spi, spi.kind + '.class')))) {
+                const varName = 'failoverSpi';
+
+                const maxAttempts = _.get(spi, spi.kind + '.maximumFailoverAttempts');
+
+                if ((spi.kind === 'JobStealing' || spi.kind === 'Always') && $generatorCommon.isDefinedAndNotEmpty(maxAttempts) && maxAttempts !== 5) {
+                    const spiCls = res.importClass($generatorCommon.failoverSpiClass(spi));
+
+                    $generatorJava.declareVariableCustom(res, varName, 'org.apache.ignite.spi.failover.FailoverSpi', 'new ' + spiCls + '()');
+
+                    if ($generatorCommon.isDefinedAndNotEmpty(spi[spi.kind].maximumFailoverAttempts))
+                        res.line('((' + spiCls + ') ' + varName + ').setMaximumFailoverAttempts(' + spi[spi.kind].maximumFailoverAttempts + ');');
+
+                    res.needEmptyLine = true;
+
+                    res.line(arrayVarName + '.add(' + varName + ');');
+                }
+                else
+                    res.line(arrayVarName + '.add(new ' + res.importClass($generatorCommon.failoverSpiClass(spi)) + '());');
+
+                res.needEmptyLine = true;
+            }
+        });
+
+        res.line('cfg.setFailoverSpi(' + arrayVarName + '.toArray(new FailoverSpi[' + arrayVarName + '.size()]));');
+
+        res.needEmptyLine = true;
+    }
+
+    return res;
+};
+
+// Generate marshaller group.
+$generatorJava.clusterLogger = function(logger, res) {
+    if (!res)
+        res = $generatorCommon.builder();
+
+    if ($generatorCommon.loggerConfigured(logger)) {
+        const varName = 'logger';
+
+        const log = logger[logger.kind];
+
+        switch (logger.kind) {
+            case 'Log4j2':
+                $generatorJava.declareVariableCustom(res, varName, 'org.apache.ignite.logger.log4j2.Log4J2Logger',
+                    'new Log4J2Logger(' + $generatorJava.toJavaCode(log.path, 'path') + ')');
+
+                res.needEmptyLine = true;
+
+                if ($generatorCommon.isDefinedAndNotEmpty(log.level))
+                    res.line(varName + '.setLevel(' + res.importClass('org.apache.logging.log4j.Level') + '.' + log.level + ');');
+
+                break;
+
+            case 'Null':
+                $generatorJava.declareVariable(res, varName, 'org.apache.ignite.logger.NullLogger');
+
+                break;
+
+            case 'Java':
+                $generatorJava.declareVariable(res, varName, 'org.apache.ignite.logger.java.JavaLogger');
+
+                break;
+
+            case 'JCL':
+                $generatorJava.declareVariable(res, varName, 'org.apache.ignite.logger.jcl.JclLogger');
+
+                break;
+
+            case 'SLF4J':
+                $generatorJava.declareVariable(res, varName, 'org.apache.ignite.logger.slf4j.Slf4jLogger');
+
+                break;
+
+            case 'Log4j':
+                if (log.mode === 'Default')
+                    $generatorJava.declareVariable(res, varName, 'org.apache.ignite.logger.log4j.Log4JLogger');
+                else {
+                    $generatorJava.declareVariableCustom(res, varName, 'org.apache.ignite.logger.log4j.Log4JLogger',
+                        'new Log4JLogger(' + $generatorJava.toJavaCode(log.path, 'path') + ')');
+                }
+
+                if ($generatorCommon.isDefinedAndNotEmpty(log.level))
+                    res.line(varName + '.setLevel(' + res.importClass('org.apache.log4j.Level') + '.' + log.level + ');');
+
+                break;
+
+            case 'Custom':
+                $generatorJava.declareVariable(res, varName, log.class);
+
+                break;
+
+            default:
+        }
+
+        res.needEmptyLine = true;
+
+        res.line('cfg.setGridLogger(' + varName + ');');
+
+        res.needEmptyLine = true;
+    }
+
+    return res;
+};
+
+// Generate marshaller group.
+$generatorJava.clusterMarshaller = function(cluster, res) {
+    if (!res)
+        res = $generatorCommon.builder();
+
+    const marshaller = cluster.marshaller;
+
+    if (marshaller && marshaller.kind) {
+        const marshallerDesc = $generatorCommon.MARSHALLERS[marshaller.kind];
+
+        $generatorJava.beanProperty(res, 'cfg', marshaller[marshaller.kind], 'marshaller', 'marshaller',
+            marshallerDesc.className, marshallerDesc.fields, true);
+
+        $generatorJava.beanProperty(res, 'marshaller', marshaller[marshaller.kind], marshallerDesc.className, marshallerDesc.fields, true);
+    }
+
+    $generatorJava.property(res, 'cfg', cluster, 'marshalLocalJobs', null, null, false);
+    $generatorJava.property(res, 'cfg', cluster, 'marshallerCacheKeepAliveTime', null, null, 10000);
+    $generatorJava.property(res, 'cfg', cluster, 'marshallerCacheThreadPoolSize', null, 'setMarshallerCachePoolSize');
+
+    res.needEmptyLine = true;
+
+    return res;
+};
+
+// Generate metrics group.
+$generatorJava.clusterMetrics = function(cluster, res) {
+    if (!res)
+        res = $generatorCommon.builder();
+
+    $generatorJava.property(res, 'cfg', cluster, 'metricsExpireTime');
+    $generatorJava.property(res, 'cfg', cluster, 'metricsHistorySize', null, null, 10000);
+    $generatorJava.property(res, 'cfg', cluster, 'metricsLogFrequency', null, null, 60000);
+    $generatorJava.property(res, 'cfg', cluster, 'metricsUpdateFrequency', null, null, 2000);
+
+    res.needEmptyLine = true;
+
+    return res;
+};
+
+// Generate swap group.
+$generatorJava.clusterSwap = function(cluster, res) {
+    if (!res)
+        res = $generatorCommon.builder();
+
+    if (cluster.swapSpaceSpi && cluster.swapSpaceSpi.kind === 'FileSwapSpaceSpi') {
+        $generatorJava.beanProperty(res, 'cfg', cluster.swapSpaceSpi.FileSwapSpaceSpi, 'swapSpaceSpi', 'swapSpi',
+            $generatorCommon.SWAP_SPACE_SPI.className, $generatorCommon.SWAP_SPACE_SPI.fields, true);
+
+        res.needEmptyLine = true;
+    }
+
+    return res;
+};
+
+// Generate time group.
+$generatorJava.clusterTime = function(cluster, res) {
+    if (!res)
+        res = $generatorCommon.builder();
+
+    $generatorJava.property(res, 'cfg', cluster, 'clockSyncSamples', null, null, 8);
+    $generatorJava.property(res, 'cfg', cluster, 'clockSyncFrequency', null, null, 120000);
+    $generatorJava.property(res, 'cfg', cluster, 'timeServerPortBase', null, null, 31100);
+    $generatorJava.property(res, 'cfg', cluster, 'timeServerPortRange', null, null, 100);
+
+    res.needEmptyLine = true;
+
+    return res;
+};
+
+// Generate thread pools group.
+$generatorJava.clusterPools = function(cluster, res) {
+    if (!res)
+        res = $generatorCommon.builder();
+
+    $generatorJava.property(res, 'cfg', cluster, 'publicThreadPoolSize');
+    $generatorJava.property(res, 'cfg', cluster, 'systemThreadPoolSize');
+    $generatorJava.property(res, 'cfg', cluster, 'managementThreadPoolSize');
+    $generatorJava.property(res, 'cfg', cluster, 'igfsThreadPoolSize');
+    $generatorJava.property(res, 'cfg', cluster, 'rebalanceThreadPoolSize');
+
+    res.needEmptyLine = true;
+
+    return res;
+};
+
+// Generate transactions group.
+$generatorJava.clusterTransactions = function(transactionConfiguration, res) {
+    if (!res)
+        res = $generatorCommon.builder();
+
+    $generatorJava.beanProperty(res, 'cfg', transactionConfiguration, 'transactionConfiguration',
+        'transactionConfiguration', $generatorCommon.TRANSACTION_CONFIGURATION.className,
+        $generatorCommon.TRANSACTION_CONFIGURATION.fields, false);
+
+    return res;
+};
+
+// Generate user attributes group.
+$generatorJava.clusterUserAttributes = function(cluster, res) {
+    if (!res)
+        res = $generatorCommon.builder();
+
+    if ($generatorCommon.isDefinedAndNotEmpty(cluster.attributes)) {
+        $generatorJava.declareVariable(res, 'attributes', 'java.util.Map', 'java.util.HashMap', 'java.lang.String', 'java.lang.String');
+
+        _.forEach(cluster.attributes, function(attr) {
+            res.line('attributes.put("' + attr.name + '", "' + attr.value + '");');
+        });
+
+        res.needEmptyLine = true;
+
+        res.line('cfg.setUserAttributes(attributes);');
+
+        res.needEmptyLine = true;
+    }
+
+    res.needEmptyLine = true;
+
+    return res;
+};
+
+
+// Generate cache general group.
+$generatorJava.cacheGeneral = function(cache, varName, res) {
+    if (!res)
+        res = $generatorCommon.builder();
+
+    if (!varName)
+        varName = $generatorJava.nextVariableName('cache', cache);
+
+    $generatorJava.property(res, varName, cache, 'name');
+
+    $generatorJava.enumProperty(res, varName, cache, 'cacheMode', 'org.apache.ignite.cache.CacheMode');
+    $generatorJava.enumProperty(res, varName, cache, 'atomicityMode', 'org.apache.ignite.cache.CacheAtomicityMode');
+
+    if (cache.cacheMode === 'PARTITIONED' && $generatorJava.property(res, varName, cache, 'backups'))
+        $generatorJava.property(res, varName, cache, 'readFromBackup');
+
+    $generatorJava.property(res, varName, cache, 'copyOnRead');
+
+    if (cache.cacheMode === 'PARTITIONED' && cache.atomicityMode === 'TRANSACTIONAL')
+        $generatorJava.property(res, varName, cache, 'invalidate');
+
+    res.needEmptyLine = true;
+
+    return res;
+};
+
+// Generate cache memory group.
+$generatorJava.cacheMemory = function(cache, varName, res) {
+    if (!res)
+        res = $generatorCommon.builder();
+
+    if (!varName)
+        varName = $generatorJava.nextVariableName('cache', cache);
+
+    $generatorJava.enumProperty(res, varName, cache, 'memoryMode', 'org.apache.ignite.cache.CacheMemoryMode', null, 'ONHEAP_TIERED');
+
+    if (cache.memoryMode !== 'OFFHEAP_VALUES')
+        $generatorJava.property(res, varName, cache, 'offHeapMaxMemory', null, null, -1);
+
+    res.softEmptyLine();
+
+    $generatorJava.evictionPolicy(res, varName, cache.evictionPolicy, 'evictionPolicy');
+
+    $generatorJava.property(res, varName, cache, 'startSize', null, null, 1500000);
+    $generatorJava.property(res, varName, cache, 'swapEnabled', null, null, false);
+
+    res.needEmptyLine = true;
+
+    return res;
+};
+
+// Generate cache query & indexing group.
+$generatorJava.cacheQuery = function(cache, domains, varName, res) {
+    if (!res)
+        res = $generatorCommon.builder();
+
+    if (!varName)
+        varName = $generatorJava.nextVariableName('cache', cache);
+
+    $generatorJava.property(res, varName, cache, 'sqlSchema');
+    $generatorJava.property(res, varName, cache, 'sqlOnheapRowCacheSize', null, null, 10240);
+    $generatorJava.property(res, varName, cache, 'longQueryWarningTimeout', null, null, 3000);
+
+    const indexedTypes = _.reduce(domains, (acc, domain) => {
+        if (domain.queryMetadata === 'Annotations') {
+            acc.push(domain.keyType);
+            acc.push(domain.valueType);
+        }
+
+        return acc;
+    }, []);
+
+    if (indexedTypes.length > 0) {
+        res.softEmptyLine();
+
+        $generatorJava.multiparamProperty(res, varName, {indexedTypes}, 'indexedTypes', 'class');
+    }
+
+    res.softEmptyLine();
+
+    $generatorJava.multiparamProperty(res, varName, cache, 'sqlFunctionClasses', 'class');
+
+    res.softEmptyLine();
+
+    $generatorJava.property(res, varName, cache, 'snapshotableIndex', null, null, false);
+    $generatorJava.property(res, varName, cache, 'sqlEscapeAll', null, null, false);
+
+    res.needEmptyLine = true;
+
+    return res;
+};
+
+/**
+ * Generate cache store datasource.
+ *
+ * @param storeFactory Factory to generate data source for.
+ * @param res Resulting output with generated code.
+ */
+$generatorJava.cacheStoreDataSource = function(storeFactory, res) {
+    const dialect = storeFactory.connectVia ? (storeFactory.connectVia === 'DataSource' ? storeFactory.dialect : null) : storeFactory.dialect;
+
+    if (dialect) {
+        const varName = 'dataSource';
+
+        const dataSourceBean = storeFactory.dataSourceBean;
+
+        const varType = res.importClass($generatorCommon.dataSourceClassName(dialect));
+
+        res.line('public static final ' + varType + ' INSTANCE_' + dataSourceBean + ' = create' + dataSourceBean + '();');
+
+        res.needEmptyLine = true;
+
+        res.startBlock('private static ' + varType + ' create' + dataSourceBean + '() {');
+        if (dialect === 'Oracle')
+            res.startBlock('try {');
+
+        $generatorJava.resetVariables(res);
+
+        $generatorJava.declareVariable(res, varName, varType);
+
+        switch (dialect) {
+            case 'Generic':
+                res.line(varName + '.setJdbcUrl(props.getProperty("' + dataSourceBean + '.jdbc.url"));');
+
+                break;
+
+            case 'DB2':
+                res.line(varName + '.setServerName(props.getProperty("' + dataSourceBean + '.jdbc.server_name"));');
+                res.line(varName + '.setPortNumber(Integer.valueOf(props.getProperty("' + dataSourceBean + '.jdbc.port_number")));');
+                res.line(varName + '.setDatabaseName(props.getProperty("' + dataSourceBean + '.jdbc.database_name"));');
+                res.line(varName + '.setDriverType(Integer.valueOf(props.getProperty("' + dataSourceBean + '.jdbc.driver_type")));');
+
+                break;
+
+            case 'PostgreSQL':
+                res.line(varName + '.setUrl(props.getProperty("' + dataSourceBean + '.jdbc.url"));');
+
+                break;
+
+            default:
+                res.line(varName + '.setURL(props.getProperty("' + dataSourceBean + '.jdbc.url"));');
+        }
+
+        res.line(varName + '.setUser(props.getProperty("' + dataSourceBean + '.jdbc.username"));');
+        res.line(varName + '.setPassword(props.getProperty("' + dataSourceBean + '.jdbc.password"));');
+
+        res.needEmptyLine = true;
+
+        res.line('return dataSource;');
+
+        if (dialect === 'Oracle') {
+            res.endBlock('}');
+            res.startBlock('catch (' + res.importClass('java.sql.SQLException') + ' ex) {');
+            res.line('throw new Error(ex);');
+            res.endBlock('}');
+        }
+
+        res.endBlock('}');
+
+        res.needEmptyLine = true;
+
+        return dataSourceBean;
+    }
+
+    return null;
+};
+
+$generatorJava.clusterDataSources = function(cluster, res) {
+    if (!res)
+        res = $generatorCommon.builder();
+
+    const datasources = [];
+
+    let storeFound = false;
+
+    function startSourcesFunction() {
+        if (!storeFound) {
+            res.line('/** Helper class for datasource creation. */');
+            res.startBlock('public static class DataSources {');
+
+            storeFound = true;
+        }
+    }
+
+    _.forEach(cluster.caches, function(cache) {
+        const factoryKind = cache.cacheStoreFactory.kind;
+
+        const storeFactory = cache.cacheStoreFactory[factoryKind];
+
+        if (storeFactory) {
+            const beanClassName = $generatorJava.dataSourceClassName(res, storeFactory);
+
+            if (beanClassName && !_.includes(datasources, beanClassName)) {
+                datasources.push(beanClassName);
+
+                if (factoryKind === 'CacheJdbcPojoStoreFactory' || factoryKind === 'CacheJdbcBlobStoreFactory') {
+                    startSourcesFunction();
+
+                    $generatorJava.cacheStoreDataSource(storeFactory, res);
+                }
+            }
+        }
+    });
+
+    if (cluster.discovery.kind === 'Jdbc') {
+        const datasource = cluster.discovery.Jdbc;
+
+        if (datasource.dataSourceBean && datasource.dialect) {
+            const beanClassName = $generatorJava.dataSourceClassName(res, datasource);
+
+            if (beanClassName && !_.includes(datasources, beanClassName)) {
+                startSourcesFunction();
+
+                $generatorJava.cacheStoreDataSource(datasource, res);
+            }
+        }
+    }
+
+    if (storeFound)
+        res.endBlock('}');
+
+    return res;
+};
+
+/**
+ * Generate cache store group.
+ *
+ * @param cache Cache descriptor.
+ * @param domains Domain model descriptors.
+ * @param cacheVarName Cache variable name.
+ * @param res Resulting output with generated code.
+ * @returns {*} Java code for cache store configuration.
+ */
+$generatorJava.cacheStore = function(cache, domains, cacheVarName, res) {
+    if (!res)
+        res = $generatorCommon.builder();
+
+    if (!cacheVarName)
+        cacheVarName = $generatorJava.nextVariableName('cache', cache);
+
+    if (cache.cacheStoreFactory && cache.cacheStoreFactory.kind) {
+        const factoryKind = cache.cacheStoreFactory.kind;
+
+        const storeFactory = cache.cacheStoreFactory[factoryKind];
+
+        if (storeFactory) {
+            const storeFactoryDesc = $generatorCommon.STORE_FACTORIES[factoryKind];
+
+            const varName = 'storeFactory' + storeFactoryDesc.suffix;
+
+            if (factoryKind === 'CacheJdbcPojoStoreFactory') {
+                // Generate POJO store factory.
+                $generatorJava.declareVariable(res, varName, 'org.apache.ignite.cache.store.jdbc.CacheJdbcPojoStoreFactory', null, null, null, true);
+                res.deep++;
+
+                res.line('/** {@inheritDoc} */');
+                res.startBlock('@Override public ' + res.importClass('org.apache.ignite.cache.store.jdbc.CacheJdbcPojoStore') + ' create() {');
+
+                res.line('setDataSource(DataSources.INSTANCE_' + storeFactory.dataSourceBean + ');');
+
+                res.needEmptyLine = true;
+
+                res.line('return super.create();');
+                res.endBlock('}');
+                res.endBlock('};');
+
+                res.needEmptyLine = true;
+
+                res.line(varName + '.setDialect(new ' +
+                    res.importClass($generatorCommon.jdbcDialectClassName(storeFactory.dialect)) + '());');
+
+                res.needEmptyLine = true;
+
+                const domainConfigs = _.filter(domains, function(domain) {
+                    return $generatorCommon.domainQueryMetadata(domain) === 'Configuration' &&
+                        $generatorCommon.isDefinedAndNotEmpty(domain.databaseTable);
+                });
+
+                if ($generatorCommon.isDefinedAndNotEmpty(domainConfigs)) {
+                    $generatorJava.declareVariable(res, 'jdbcTypes', 'java.util.Collection', 'java.util.ArrayList', 'org.apache.ignite.cache.store.jdbc.JdbcType');
+
+                    res.needEmptyLine = true;
+
+                    _.forEach(domainConfigs, function(domain) {
+                        if ($generatorCommon.isDefinedAndNotEmpty(domain.databaseTable))
+                            res.line('jdbcTypes.add(jdbcType' + $generatorJava.extractType(domain.valueType) + '(' + cacheVarName + '.getName()));');
+                    });
+
+                    res.needEmptyLine = true;
+
+                    res.line(varName + '.setTypes(jdbcTypes.toArray(new JdbcType[jdbcTypes.size()]));');
+
+                    res.needEmptyLine = true;
+                }
+
+                res.line(cacheVarName + '.setCacheStoreFactory(' + varName + ');');
+            }
+            else if (factoryKind === 'CacheJdbcBlobStoreFactory') {
+                // Generate POJO store factory.
+                $generatorJava.declareVariable(res, varName, 'org.apache.ignite.cache.store.jdbc.CacheJdbcBlobStoreFactory', null, null, null, storeFactory.connectVia === 'DataSource');
+
+                if (storeFactory.connectVia === 'DataSource') {
+                    res.deep++;
+
+                    res.line('/** {@inheritDoc} */');
+                    res.startBlock('@Override public ' + res.importClass('org.apache.ignite.cache.store.jdbc.CacheJdbcBlobStore') + ' create() {');
+
+                    res.line('setDataSource(DataSources.INSTANCE_' + storeFactory.dataSourceBean + ');');
+
+                    res.needEmptyLine = true;
+
+                    res.line('return super.create();');
+                    res.endBlock('}');
+                    res.endBlock('};');
+
+                    res.needEmptyLine = true;
+
+                    $generatorJava.property(res, varName, storeFactory, 'initSchema');
+                    $generatorJava.property(res, varName, storeFactory, 'createTableQuery');
+                    $generatorJava.property(res, varName, storeFactory, 'loadQuery');
+                    $generatorJava.property(res, varName, storeFactory, 'insertQuery');
+                    $generatorJava.property(res, varName, storeFactory, 'updateQuery');
+                    $generatorJava.property(res, varName, storeFactory, 'deleteQuery');
+                }
+                else {
+                    $generatorJava.property(res, varName, storeFactory, 'connectionUrl');
+
+                    if (storeFactory.user) {
+                        $generatorJava.property(res, varName, storeFactory, 'user');
+                        res.line(varName + '.setPassword(props.getProperty("ds.' + storeFactory.user + '.password"));');
+                    }
+                }
+
+                res.needEmptyLine = true;
+
+                res.line(cacheVarName + '.setCacheStoreFactory(' + varName + ');');
+            }
+            else
+                $generatorJava.beanProperty(res, cacheVarName, storeFactory, 'cacheStoreFactory', varName, storeFactoryDesc.className, storeFactoryDesc.fields, true);
+
+            res.needEmptyLine = true;
+        }
+    }
+
+    res.softEmptyLine();
+
+    $generatorJava.property(res, cacheVarName, cache, 'storeKeepBinary', null, null, false);
+    $generatorJava.property(res, cacheVarName, cache, 'loadPreviousValue', null, null, false);
+    $generatorJava.property(res, cacheVarName, cache, 'readThrough', null, null, false);
+    $generatorJava.property(res, cacheVarName, cache, 'writeThrough', null, null, false);
+
+    res.softEmptyLine();
+
+    if (cache.writeBehindEnabled) {
+        $generatorJava.property(res, cacheVarName, cache, 'writeBehindEnabled', null, null, false);
+        $generatorJava.property(res, cacheVarName, cache, 'writeBehindBatchSize', null, null, 512);
+        $generatorJava.property(res, cacheVarName, cache, 'writeBehindFlushSize', null, null, 10240);
+        $generatorJava.property(res, cacheVarName, cache, 'writeBehindFlushFrequency', null, null, 5000);
+        $generatorJava.property(res, cacheVarName, cache, 'writeBehindFlushThreadCount', null, null, 1);
+    }
+
+    res.needEmptyLine = true;
+
+    return res;
+};
+
+// Generate cache node filter group.
+$generatorJava.cacheNodeFilter = function(cache, igfss, varName, res) {
+    if (!res)
+        res = $generatorCommon.builder();
+
+    if (!varName)
+        varName = $generatorJava.nextVariableName('cache', cache);
+
+    switch (_.get(cache, 'nodeFilter.kind')) {
+        case 'IGFS':
+            const foundIgfs = _.find(igfss, (igfs) => igfs._id === cache.nodeFilter.IGFS.igfs);
+
+            if (foundIgfs) {
+                const predClsName = res.importClass('org.apache.ignite.internal.processors.igfs.IgfsNodePredicate');
+
+                res.line(`${varName}.setNodeFilter(new ${predClsName}("${foundIgfs.name}"));`);
+            }
+
+            break;
+
+        case 'OnNodes':
+            const nodes = cache.nodeFilter.OnNodes.nodeIds;
+
+            if ($generatorCommon.isDefinedAndNotEmpty(nodes)) {
+                const startQuote = res.importClass('java.util.UUID') + '.fromString("';
+
+                $generatorJava.fxVarArgs(res, varName + '.setNodeFilter(new ' +
+                    res.importClass('org.apache.ignite.internal.util.lang.GridNodePredicate'), true, nodes, '(', '))',
+                    startQuote, '")');
+            }
+
+            break;
+
+        case 'Custom':
+            res.line(varName + '.setNodeFilter(new ' + res.importClass(cache.nodeFilter.Custom.className) + '());');
+
+            break;
+
+        default: break;
+    }
+
+    res.needEmptyLine = true;
+
+    return res;
+};
+
+// Generate cache concurrency group.
+$generatorJava.cacheConcurrency = function(cache, varName, res) {
+    if (!res)
+        res = $generatorCommon.builder();
+
+    if (!varName)
+        varName = $generatorJava.nextVariableName('cache', cache);
+
+    $generatorJava.property(res, varName, cache, 'maxConcurrentAsyncOperations', null, null, 500);
+    $generatorJava.property(res, varName, cache, 'defaultLockTimeout', null, null, 0);
+    $generatorJava.enumProperty(res, varName, cache, 'atomicWriteOrderMode', 'org.apache.ignite.cache.CacheAtomicWriteOrderMode');
+    $generatorJava.enumProperty(res, varName, cache, 'writeSynchronizationMode', 'org.apache.ignite.cache.CacheWriteSynchronizationMode', null, 'PRIMARY_SYNC');
+
+    res.needEmptyLine = true;
+
+    return res;
+};
+
+// Generate cache rebalance group.
+$generatorJava.cacheRebalance = function(cache, varName, res) {
+    if (!res)
+        res = $generatorCommon.builder();
+
+    if (!varName)
+        varName = $generatorJava.nextVariableName('cache', cache);
+
+    if (cache.cacheMode !== 'LOCAL') {
+        $generatorJava.enumProperty(res, varName, cache, 'rebalanceMode', 'org.apache.ignite.cache.CacheRebalanceMode', null, 'ASYNC');
+        $generatorJava.property(res, varName, cache, 'rebalanceThreadPoolSize', null, null, 1);
+        $generatorJava.property(res, varName, cache, 'rebalanceBatchSize', null, null, 524288);
+        $generatorJava.property(res, varName, cache, 'rebalanceBatchesPrefetchCount', null, null, 2);
+        $generatorJava.property(res, varName, cache, 'rebalanceOrder', null, null, 0);
+        $generatorJava.property(res, varName, cache, 'rebalanceDelay', null, null, 0);
+        $generatorJava.property(res, varName, cache, 'rebalanceTimeout', null, null, 10000);
+        $generatorJava.property(res, varName, cache, 'rebalanceThrottle', null, null, 0);
+    }
+
+    res.softEmptyLine();
+
+    if (cache.igfsAffinnityGroupSize) {
+        res.line(varName + '.setAffinityMapper(new ' + res.importClass('org.apache.ignite.igfs.IgfsGroupDataBlocksKeyMapper') + '(' + cache.igfsAffinnityGroupSize + '));');
+
+        res.needEmptyLine = true;
+    }
+
+    return res;
+};
+
+// Generate cache server near cache group.
+$generatorJava.cacheServerNearCache = function(cache, varName, res) {
+    if (!res)
+        res = $generatorCommon.builder();
+
+    if (!varName)
+        varName = $generatorJava.nextVariableName('cache', cache);
+
+    if (cache.cacheMode === 'PARTITIONED' && cache.nearCacheEnabled) {
+        res.needEmptyLine = true;
+
+        if (cache.nearConfiguration) {
+            $generatorJava.declareVariable(res, 'nearCfg', 'org.apache.ignite.configuration.NearCacheConfiguration');
+
+            res.needEmptyLine = true;
+
+            if (cache.nearConfiguration.nearStartSize) {
+                $generatorJava.property(res, 'nearCfg', cache.nearConfiguration, 'nearStartSize', null, null, 375000);
+
+                res.needEmptyLine = true;
+            }
+
+            if (cache.nearConfiguration.nearEvictionPolicy && cache.nearConfiguration.nearEvictionPolicy.kind) {
+                $generatorJava.evictionPolicy(res, 'nearCfg', cache.nearConfiguration.nearEvictionPolicy, 'nearEvictionPolicy');
+
+                res.needEmptyLine = true;
+            }
+
+            res.line(varName + '.setNearConfiguration(nearCfg);');
+
+            res.needEmptyLine = true;
+        }
+    }
+
+    return res;
+};
+
+// Generate cache statistics group.
+$generatorJava.cacheStatistics = function(cache, varName, res) {
+    if (!res)
+        res = $generatorCommon.builder();
+
+    if (!varName)
+        varName = $generatorJava.nextVariableName('cache', cache);
+
+    $generatorJava.property(res, varName, cache, 'statisticsEnabled', null, null, false);
+    $generatorJava.property(res, varName, cache, 'managementEnabled', null, null, false);
+
+    res.needEmptyLine = true;
+
+    return res;
+};
+
+// Generate domain model query fields.
+$generatorJava.domainModelQueryFields = function(res, domain) {
+    const fields = domain.fields;
+
+    if (fields && fields.length > 0) {
+        $generatorJava.declareVariable(res, 'fields', 'java.util.LinkedHashMap', 'java.util.LinkedHashMap', 'java.lang.String', 'java.lang.String');
+
+        _.forEach(fields, function(field) {
+            res.line('fields.put("' + field.name + '", "' + $generatorCommon.JavaTypes.fullClassName(field.className) + '");');
+        });
+
+        res.needEmptyLine = true;
+
+        res.line('qryMeta.setFields(fields);');
+
+        res.needEmptyLine = true;
+    }
+};
+
+// Generate domain model query aliases.
+$generatorJava.domainModelQueryAliases = function(res, domain) {
+    const aliases = domain.aliases;
+
+    if (aliases && aliases.length > 0) {
+        $generatorJava.declareVariable(res, 'aliases', 'java.util.Map', 'java.util.HashMap', 'java.lang.String', 'java.lang.String');
+
+        _.forEach(aliases, function(alias) {
+            res.line('aliases.put("' + alias.field + '", "' + alias.alias + '");');
+        });
+
+        res.needEmptyLine = true;
+
+        res.line('qryMeta.setAliases(aliases);');
+
+        res.needEmptyLine = true;
+    }
+};
+
+// Generate domain model indexes.
+$generatorJava.domainModelQueryIndexes = function(res, domain) {
+    const indexes = domain.indexes;
+
+    if (indexes && indexes.length > 0) {
+        res.needEmptyLine = true;
+
+        $generatorJava.declareVariable(res, 'indexes', 'java.util.List', 'java.util.ArrayList', 'org.apache.ignite.cache.QueryIndex');
+
+        _.forEach(indexes, function(index) {
+            const fields = index.fields;
+
+            // One row generation for 1 field index.
+            if (fields && fields.length === 1) {
+                const field = index.fields[0];
+
+                res.line('indexes.add(new ' + res.importClass('org.apache.ignite.cache.QueryIndex') +
+                    '("' + field.name + '", ' +
+                    res.importClass('org.apache.ignite.cache.QueryIndexType') + '.' + index.indexType + ', ' +
+                    field.direction + ', "' + index.name + '"));');
+            }
+            else {
+                res.needEmptyLine = true;
+
+                $generatorJava.declareVariable(res, 'index', 'org.apache.ignite.cache.QueryIndex');
+
+                $generatorJava.property(res, 'index', index, 'name');
+                $generatorJava.enumProperty(res, 'index', index, 'indexType', 'org.apache.ignite.cache.QueryIndexType');
+
+                res.needEmptyLine = true;
+
+                if (fields && fields.length > 0) {
+                    $generatorJava.declareVariable(res, 'indFlds', 'java.util.LinkedHashMap', 'java.util.LinkedHashMap', 'String', 'Boolean');
+
+                    _.forEach(fields, function(field) {
+                        res.line('indFlds.put("' + field.name + '", ' + field.direction + ');');
+                    });
+
+                    res.needEmptyLine = true;
+
+                    res.line('index.setFields(indFlds);');
+
+                    res.needEmptyLine = true;
+                }
+
+                res.line('indexes.add(index);');
+            }
+        });
+
+        res.needEmptyLine = true;
+
+        res.line('qryMeta.setIndexes(indexes);');
+
+        res.needEmptyLine = true;
+    }
+};
+
+// Generate domain model db fields.
+$generatorJava.domainModelDatabaseFields = function(res, domain, fieldProperty) {
+    const dbFields = domain[fieldProperty];
+
+    if (dbFields && dbFields.length > 0) {
+        res.needEmptyLine = true;
+
+        res.importClass('java.sql.Types');
+
+        res.startBlock('jdbcType.' + $generatorCommon.toJavaName('set', fieldProperty) + '(');
+
+        const lastIx = dbFields.length - 1;
+
+        res.importClass('org.apache.ignite.cache.store.jdbc.JdbcTypeField');
+
+        _.forEach(dbFields, function(field, ix) {
+            res.line('new JdbcTypeField(' +
+                'Types.' + field.databaseFieldType + ', ' + '"' + field.databaseFieldName + '", ' +
+                res.importClass(field.javaFieldType) + '.class, ' + '"' + field.javaFieldName + '"' + ')' + (ix < lastIx ? ',' : ''));
+        });
+
+        res.endBlock(');');
+
+        res.needEmptyLine = true;
+    }
+};
+
+// Generate domain model general group.
+$generatorJava.domainModelGeneral = function(domain, res) {
+    if (!res)
+        res = $generatorCommon.builder();
+
+    switch ($generatorCommon.domainQueryMetadata(domain)) {
+        case 'Annotations':
+            if ($generatorCommon.isDefinedAndNotEmpty(domain.keyType) || $generatorCommon.isDefinedAndNotEmpty(domain.valueType)) {
+                const types = [];
+
+                if ($generatorCommon.isDefinedAndNotEmpty(domain.keyType))
+                    types.push($generatorJava.toJavaCode(res.importClass(domain.keyType), 'class'));
+                else
+                    types.push('???');
+
+                if ($generatorCommon.isDefinedAndNotEmpty(domain.valueType))
+                    types.push($generatorJava.toJavaCode(res.importClass(domain.valueType), 'class'));
+                else
+                    types.push('???');
+
+                if ($generatorCommon.isDefinedAndNotEmpty(types))
+                    $generatorJava.fxVarArgs(res, 'cache.setIndexedTypes', false, types);
+            }
+
+            break;
+
+        case 'Configuration':
+            $generatorJava.classNameProperty(res, 'jdbcTypes', domain, 'keyType');
+            $generatorJava.property(res, 'jdbcTypes', domain, 'valueType');
+
+            if ($generatorCommon.isDefinedAndNotEmpty(domain.fields)) {
+                res.needEmptyLine = true;
+
+                $generatorJava.classNameProperty(res, 'qryMeta', domain, 'keyType');
+                $generatorJava.property(res, 'qryMeta', domain, 'valueType');
+            }
+
+            break;
+
+        default:
+    }
+
+    res.needEmptyLine = true;
+
+    return res;
+};
+
+// Generate domain model for query group.
+$generatorJava.domainModelQuery = function(domain, res) {
+    if (!res)
+        res = $generatorCommon.builder();
+
+    if ($generatorCommon.domainQueryMetadata(domain) === 'Configuration') {
+        $generatorJava.domainModelQueryFields(res, domain);
+        $generatorJava.domainModelQueryAliases(res, domain);
+        $generatorJava.domainModelQueryIndexes(res, domain);
+
+        res.needEmptyLine = true;
+    }
+
+    return res;
+};
+
+// Generate domain model for store group.
+$generatorJava.domainStore = function(domain, withTypes, res) {
+    if (!res)
+        res = $generatorCommon.builder();
+
+    $generatorJava.property(res, 'jdbcType', domain, 'databaseSchema');
+    $generatorJava.property(res, 'jdbcType', domain, 'databaseTable');
+
+    if (withTypes) {
+        $generatorJava.classNameProperty(res, 'jdbcType', domain, 'keyType');
+        $generatorJava.property(res, 'jdbcType', domain, 'valueType');
+    }
+
+    $generatorJava.domainModelDatabaseFields(res, domain, 'keyFields');
+    $generatorJava.domainModelDatabaseFields(res, domain, 'valueFields');
+
+    res.needEmptyLine = true;
+
+    return res;
+};
+
+// Generate domain model configs.
+$generatorJava.cacheDomains = function(domains, varName, res) {
+    if (!res)
+        res = $generatorCommon.builder();
+
+    const domainConfigs = _.filter(domains, function(domain) {
+        return $generatorCommon.domainQueryMetadata(domain) === 'Configuration' &&
+            $generatorCommon.isDefinedAndNotEmpty(domain.fields);
+    });
+
+    // Generate domain model configs.
+    if ($generatorCommon.isDefinedAndNotEmpty(domainConfigs)) {
+        $generatorJava.declareVariable(res, 'queryEntities', 'java.util.Collection', 'java.util.ArrayList', 'org.apache.ignite.cache.QueryEntity');
+
+        _.forEach(domainConfigs, function(domain) {
+            if ($generatorCommon.isDefinedAndNotEmpty(domain.fields))
+                res.line('queryEntities.add(queryEntity' + $generatorJava.extractType(domain.valueType) + '());');
+        });
+
+        res.needEmptyLine = true;
+
+        res.line(varName + '.setQueryEntities(queryEntities);');
+
+        res.needEmptyLine = true;
+    }
+
+    return res;
+};
+
+// Generate cache configs.
+$generatorJava.cache = function(cache, varName, res) {
+    if (!res)
+        res = $generatorCommon.builder();
+
+    $generatorJava.cacheGeneral(cache, varName, res);
+    $generatorJava.cacheMemory(cache, varName, res);
+    $generatorJava.cacheQuery(cache, cache.domains, varName, res);
+    $generatorJava.cacheStore(cache, cache.domains, varName, res);
+
+    const igfs = _.get(cache, 'nodeFilter.IGFS.instance');
+
+    $generatorJava.cacheNodeFilter(cache, igfs ? [igfs] : [], varName, res);
+    $generatorJava.cacheConcurrency(cache, varName, res);
+    $generatorJava.cacheRebalance(cache, varName, res);
+    $generatorJava.cacheServerNearCache(cache, varName, res);
+    $generatorJava.cacheStatistics(cache, varName, res);
+    $generatorJava.cacheDomains(cache.domains, varName, res);
+};
+
+// Generation of cache domain model in separate methods.
+$generatorJava.clusterDomains = function(caches, res) {
+    const domains = [];
+
+    const typeVarName = 'jdbcType';
+    const metaVarName = 'qryMeta';
+
+    _.forEach(caches, function(cache) {
+        _.forEach(cache.domains, function(domain) {
+            if (_.isNil(_.find(domains, function(m) {
+                return m === domain.valueType;
+            }))) {
+                $generatorJava.resetVariables(res);
+
+                const type = $generatorJava.extractType(domain.valueType);
+
+                if ($generatorCommon.isDefinedAndNotEmpty(domain.databaseTable)) {
+                    res.line('/**');
+                    res.line(' * Create JDBC type for ' + type + '.');
+                    res.line(' *');
+                    res.line(' * @param cacheName Cache name.');
+                    res.line(' * @return Configured JDBC type.');
+                    res.line(' */');
+                    res.startBlock('private static JdbcType jdbcType' + type + '(String cacheName) {');
+
+                    $generatorJava.declareVariable(res, typeVarName, 'org.apache.ignite.cache.store.jdbc.JdbcType');
+
+                    res.needEmptyLine = true;
+
+                    res.line(typeVarName + '.setCacheName(cacheName);');
+
+                    $generatorJava.domainStore(domain, true, res);
+
+                    res.needEmptyLine = true;
+
+                    res.line('return ' + typeVarName + ';');
+                    res.endBlock('}');
+
+                    res.needEmptyLine = true;
+                }
+
+                if ($generatorCommon.domainQueryMetadata(domain) === 'Configuration' &&
+                    $generatorCommon.isDefinedAndNotEmpty(domain.fields)) {
+                    res.line('/**');
+                    res.line(' * Create SQL Query descriptor for ' + type + '.');
+                    res.line(' *');
+                    res.line(' * @return Configured query entity.');
+                    res.line(' */');
+                    res.startBlock('private static QueryEntity queryEntity' + type + '() {');
+
+                    $generatorJava.declareVariable(res, metaVarName, 'org.apache.ignite.cache.QueryEntity');
+
+                    $generatorJava.classNameProperty(res, metaVarName, domain, 'keyType');
+                    $generatorJava.property(res, metaVarName, domain, 'valueType');
+
+                    res.needEmptyLine = true;
+
+                    $generatorJava.domainModelQuery(domain, res);
+
+                    res.emptyLineIfNeeded();
+                    res.line('return ' + metaVarName + ';');
+
+                    res.needEmptyLine = true;
+
+                    res.endBlock('}');
+                }
+
+                domains.push(domain.valueType);
+            }
+        });
+    });
+};
+
+/**
+ * @param prefix Variable prefix.
+ * @param obj Object to process.
+ * @param names Known names to generate next unique name.
+ */
+$generatorJava.nextVariableName = function(prefix, obj, names) {
+    let nextName = $generatorCommon.toJavaName(prefix, obj.name);
+
+    let ix = 0;
+
+    const checkNextName = (name) => name === nextName + (ix === 0 ? '' : '_' + ix);
+
+    while (_.find(names, (name) => checkNextName(name)))
+        ix++;
+
+    if (ix > 0)
+        nextName = nextName + '_' + ix;
+
+    return nextName;
+};
+
+// Generate cluster caches.
+$generatorJava.clusterCaches = function(caches, igfss, isSrvCfg, res) {
+    function clusterCache(cache, names) {
+        res.emptyLineIfNeeded();
+
+        const cacheName = $generatorJava.nextVariableName('cache', cache, names);
+
+        $generatorJava.resetVariables(res);
+
+        const hasDatasource = $generatorCommon.cacheHasDatasource(cache);
+
+        res.line('/**');
+        res.line(' * Create configuration for cache "' + cache.name + '".');
+        res.line(' *');
+        res.line(' * @return Configured cache.');
+
+        if (hasDatasource)
+            res.line(' * @throws Exception if failed to create cache configuration.');
+
+        res.line(' */');
+        res.startBlock('public static CacheConfiguration ' + cacheName + '()' + (hasDatasource ? ' throws Exception' : '') + ' {');
+
+        $generatorJava.declareVariable(res, cacheName, 'org.apache.ignite.configuration.CacheConfiguration');
+
+        $generatorJava.cache(cache, cacheName, res);
+
+        res.line('return ' + cacheName + ';');
+        res.endBlock('}');
+
+        names.push(cacheName);
+
+        res.needEmptyLine = true;
+    }
+
+    if (!res)
+        res = $generatorCommon.builder();
+
+    const names = [];
+
+    if ($generatorCommon.isDefinedAndNotEmpty(caches)) {
+        res.emptyLineIfNeeded();
+
+        _.forEach(caches, function(cache) {
+            clusterCache(cache, names);
+        });
+
+        res.needEmptyLine = true;
+    }
+
+    if (isSrvCfg && $generatorCommon.isDefinedAndNotEmpty(igfss)) {
+        res.emptyLineIfNeeded();
+
+        _.forEach(igfss, function(igfs) {
+            clusterCache($generatorCommon.igfsDataCache(igfs), names);
+            clusterCache($generatorCommon.igfsMetaCache(igfs), names);
+        });
+
+        res.needEmptyLine = true;
+    }
+
+    return res;
+};
+
+// Generate cluster caches.
+$generatorJava.clusterCacheUse = function(caches, igfss, res) {
+    function clusterCacheInvoke(cache, names) {
+        names.push($generatorJava.nextVariableName('cache', cache, names));
+    }
+
+    if (!res)
+        res = $generatorCommon.builder();
+
+    const cacheNames = [];
+
+    _.forEach(caches, function(cache) {
+        clusterCacheInvoke(cache, cacheNames);
+    });
+
+    const igfsNames = [];
+
+    _.forEach(igfss, function(igfs) {
+        clusterCacheInvoke($generatorCommon.igfsDataCache(igfs), igfsNames);
+        clusterCacheInvoke($generatorCommon.igfsMetaCache(igfs), igfsNames);
+    });
+
+    const allCacheNames = cacheNames.concat(igfsNames);
+
+    if (allCacheNames.length) {
+        res.line('cfg.setCacheConfiguration(' + allCacheNames.join('(), ') + '());');
+
+        res.needEmptyLine = true;
+    }
+
+    return res;
+};
+
+// Get class name from fully specified class path.
+$generatorJava.extractType = function(fullType) {
+    return fullType.substring(fullType.lastIndexOf('.') + 1);
+};
+
+/**
+ * Generate java class code.
+ *
+ * @param domain Domain model object.
+ * @param key If 'true' then key class should be generated.
+ * @param pkg Package name.
+ * @param useConstructor If 'true' then empty and full constructors should be generated.
+ * @param includeKeyFields If 'true' then include key fields into value POJO.
+ * @param res Resulting output with generated code.
+ */
+$generatorJava.javaClassCode = function(domain, key, pkg, useConstructor, includeKeyFields, res) {
+    if (!res)
+        res = $generatorCommon.builder();
+
+    const type = $generatorJava.extractType(key ? domain.keyType : domain.valueType);
+
+    // Class comment.
+    res.line('/**');
+    res.line(' * ' + type + ' definition.');
+    res.line(' *');
+    res.line(' * ' + $generatorCommon.mainComment());
+    res.line(' */');
+
+    res.startBlock('public class ' + type + ' implements ' + res.importClass('java.io.Serializable') + ' {');
+
+    res.line('/** */');
+    res.line('private static final lo

<TRUNCATED>

[04/52] ignite git commit: Web Console beta-3.

Posted by ak...@apache.org.
http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/src/main/js/serve/routes/demo/domains.json
----------------------------------------------------------------------
diff --git a/modules/web-console/src/main/js/serve/routes/demo/domains.json b/modules/web-console/src/main/js/serve/routes/demo/domains.json
deleted file mode 100644
index 980d8d1..0000000
--- a/modules/web-console/src/main/js/serve/routes/demo/domains.json
+++ /dev/null
@@ -1,307 +0,0 @@
-[
-  {
-    "keyType": "Integer",
-    "valueType": "model.Parking",
-    "queryMetadata": "Configuration",
-    "databaseSchema": "CARS",
-    "databaseTable": "PARKING",
-    "indexes": [],
-    "aliases": [],
-    "fields": [
-      {
-        "name": "name",
-        "className": "String"
-      },
-      {
-        "name": "capacity",
-        "className": "Integer"
-      }
-    ],
-    "valueFields": [
-      {
-        "databaseFieldName": "NAME",
-        "databaseFieldType": "VARCHAR",
-        "javaFieldName": "name",
-        "javaFieldType": "String"
-      },
-      {
-        "databaseFieldName": "CAPACITY",
-        "databaseFieldType": "INTEGER",
-        "javaFieldName": "capacity",
-        "javaFieldType": "int"
-      }
-    ],
-    "keyFields": [
-      {
-        "databaseFieldName": "ID",
-        "databaseFieldType": "INTEGER",
-        "javaFieldName": "id",
-        "javaFieldType": "int"
-      }
-    ],
-    "caches": []
-  },
-  {
-    "keyType": "Integer",
-    "valueType": "model.Department",
-    "queryMetadata": "Configuration",
-    "databaseSchema": "PUBLIC",
-    "databaseTable": "DEPARTMENT",
-    "indexes": [],
-    "aliases": [],
-    "fields": [
-      {
-        "name": "countryId",
-        "className": "Integer"
-      },
-      {
-        "name": "name",
-        "className": "String"
-      }
-    ],
-    "valueFields": [
-      {
-        "databaseFieldName": "COUNTRY_ID",
-        "databaseFieldType": "INTEGER",
-        "javaFieldName": "countryId",
-        "javaFieldType": "int"
-      },
-      {
-        "databaseFieldName": "NAME",
-        "databaseFieldType": "VARCHAR",
-        "javaFieldName": "name",
-        "javaFieldType": "String"
-      }
-    ],
-    "keyFields": [
-      {
-        "databaseFieldName": "ID",
-        "databaseFieldType": "INTEGER",
-        "javaFieldName": "id",
-        "javaFieldType": "int"
-      }
-    ],
-    "caches": []
-  },
-  {
-    "keyType": "Integer",
-    "valueType": "model.Employee",
-    "queryMetadata": "Configuration",
-    "databaseSchema": "PUBLIC",
-    "databaseTable": "EMPLOYEE",
-    "indexes": [
-      {
-        "name": "EMP_NAMES",
-        "indexType": "SORTED",
-        "fields": [
-          {
-            "name": "firstName",
-            "direction": true
-          },
-          {
-            "name": "lastName",
-            "direction": true
-          }
-        ]
-      },
-      {
-        "name": "EMP_SALARY",
-        "indexType": "SORTED",
-        "fields": [
-          {
-            "name": "salary",
-            "direction": true
-          }
-        ]
-      }
-    ],
-    "aliases": [],
-    "fields": [
-      {
-        "name": "departmentId",
-        "className": "Integer"
-      },
-      {
-        "name": "managerId",
-        "className": "Integer"
-      },
-      {
-        "name": "firstName",
-        "className": "String"
-      },
-      {
-        "name": "lastName",
-        "className": "String"
-      },
-      {
-        "name": "email",
-        "className": "String"
-      },
-      {
-        "name": "phoneNumber",
-        "className": "String"
-      },
-      {
-        "name": "hireDate",
-        "className": "Date"
-      },
-      {
-        "name": "job",
-        "className": "String"
-      },
-      {
-        "name": "salary",
-        "className": "Double"
-      }
-    ],
-    "valueFields": [
-      {
-        "databaseFieldName": "DEPARTMENT_ID",
-        "databaseFieldType": "INTEGER",
-        "javaFieldName": "departmentId",
-        "javaFieldType": "int"
-      },
-      {
-        "databaseFieldName": "MANAGER_ID",
-        "databaseFieldType": "INTEGER",
-        "javaFieldName": "managerId",
-        "javaFieldType": "Integer"
-      },
-      {
-        "databaseFieldName": "FIRST_NAME",
-        "databaseFieldType": "VARCHAR",
-        "javaFieldName": "firstName",
-        "javaFieldType": "String"
-      },
-      {
-        "databaseFieldName": "LAST_NAME",
-        "databaseFieldType": "VARCHAR",
-        "javaFieldName": "lastName",
-        "javaFieldType": "String"
-      },
-      {
-        "databaseFieldName": "EMAIL",
-        "databaseFieldType": "VARCHAR",
-        "javaFieldName": "email",
-        "javaFieldType": "String"
-      },
-      {
-        "databaseFieldName": "PHONE_NUMBER",
-        "databaseFieldType": "VARCHAR",
-        "javaFieldName": "phoneNumber",
-        "javaFieldType": "String"
-      },
-      {
-        "databaseFieldName": "HIRE_DATE",
-        "databaseFieldType": "DATE",
-        "javaFieldName": "hireDate",
-        "javaFieldType": "Date"
-      },
-      {
-        "databaseFieldName": "JOB",
-        "databaseFieldType": "VARCHAR",
-        "javaFieldName": "job",
-        "javaFieldType": "String"
-      },
-      {
-        "databaseFieldName": "SALARY",
-        "databaseFieldType": "DOUBLE",
-        "javaFieldName": "salary",
-        "javaFieldType": "Double"
-      }
-    ],
-    "keyFields": [
-      {
-        "databaseFieldName": "ID",
-        "databaseFieldType": "INTEGER",
-        "javaFieldName": "id",
-        "javaFieldType": "int"
-      }
-    ],
-    "caches": []
-  },
-  {
-    "keyType": "Integer",
-    "valueType": "model.Country",
-    "queryMetadata": "Configuration",
-    "databaseSchema": "PUBLIC",
-    "databaseTable": "COUNTRY",
-    "indexes": [],
-    "aliases": [],
-    "fields": [
-      {
-        "name": "name",
-        "className": "String"
-      },
-      {
-        "name": "population",
-        "className": "Integer"
-      }
-    ],
-    "valueFields": [
-      {
-        "databaseFieldName": "NAME",
-        "databaseFieldType": "VARCHAR",
-        "javaFieldName": "name",
-        "javaFieldType": "String"
-      },
-      {
-        "databaseFieldName": "POPULATION",
-        "databaseFieldType": "INTEGER",
-        "javaFieldName": "population",
-        "javaFieldType": "int"
-      }
-    ],
-    "keyFields": [
-      {
-        "databaseFieldName": "ID",
-        "databaseFieldType": "INTEGER",
-        "javaFieldName": "id",
-        "javaFieldType": "int"
-      }
-    ],
-    "caches": []
-  },
-  {
-    "keyType": "Integer",
-    "valueType": "model.Car",
-    "queryMetadata": "Configuration",
-    "databaseSchema": "CARS",
-    "databaseTable": "CAR",
-    "indexes": [],
-    "aliases": [],
-    "fields": [
-      {
-        "name": "parkingId",
-        "className": "Integer"
-      },
-      {
-        "name": "name",
-        "className": "String"
-      }
-    ],
-    "valueFields": [
-      {
-        "databaseFieldName": "PARKING_ID",
-        "databaseFieldType": "INTEGER",
-        "javaFieldName": "parkingId",
-        "javaFieldType": "int"
-      },
-      {
-        "databaseFieldName": "NAME",
-        "databaseFieldType": "VARCHAR",
-        "javaFieldName": "name",
-        "javaFieldType": "String"
-      }
-    ],
-    "keyFields": [
-      {
-        "databaseFieldName": "ID",
-        "databaseFieldType": "INTEGER",
-        "javaFieldName": "id",
-        "javaFieldType": "int"
-      }
-    ],
-    "caches": []
-  }
-]

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/src/main/js/serve/routes/demo/igfss.json
----------------------------------------------------------------------
diff --git a/modules/web-console/src/main/js/serve/routes/demo/igfss.json b/modules/web-console/src/main/js/serve/routes/demo/igfss.json
deleted file mode 100644
index cd128a6..0000000
--- a/modules/web-console/src/main/js/serve/routes/demo/igfss.json
+++ /dev/null
@@ -1,10 +0,0 @@
-[
-  {
-    "ipcEndpointEnabled": true,
-    "fragmentizerEnabled": true,
-    "name": "igfs",
-    "dataCacheName": "igfs-data",
-    "metaCacheName": "igfs-meta",
-    "clusters": []
-  }
-]

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/src/main/js/serve/routes/domains.js
----------------------------------------------------------------------
diff --git a/modules/web-console/src/main/js/serve/routes/domains.js b/modules/web-console/src/main/js/serve/routes/domains.js
deleted file mode 100644
index 9dbf418..0000000
--- a/modules/web-console/src/main/js/serve/routes/domains.js
+++ /dev/null
@@ -1,195 +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.
- */
-
-'use strict';
-
-// Fire me up!
-
-module.exports = {
-    implements: 'domains-routes',
-    inject: ['require(lodash)', 'require(express)', 'mongo']
-};
-
-module.exports.factory = (_, express, mongo) => {
-    return new Promise((factoryResolve) => {
-        const router = new express.Router();
-
-        /**
-         * Get spaces and domain models accessed for user account.
-         *
-         * @param req Request.
-         * @param res Response.
-         */
-        router.post('/list', (req, res) => {
-            const result = {};
-            let spacesIds = [];
-
-            mongo.spaces(req.currentUserId(), req.header('IgniteDemoMode'))
-                .then((spaces) => {
-                    result.spaces = spaces;
-                    spacesIds = spaces.map((space) => space._id);
-
-                    return mongo.Cluster.find({space: {$in: spacesIds}}, '_id name').sort('name').lean().exec();
-                })
-                .then((clusters) => {
-                    result.clusters = clusters;
-
-                    return mongo.Cache.find({space: {$in: spacesIds}}).sort('name').lean().exec();
-                })
-                .then((caches) => {
-                    result.caches = caches;
-
-                    return mongo.DomainModel.find({space: {$in: spacesIds}}).sort('valueType').lean().exec();
-                })
-                .then((domains) => {
-                    result.domains = domains;
-
-                    res.json(result);
-                })
-                .catch((err) => mongo.handleError(res, err));
-        });
-
-        function _updateCacheStore(cacheStoreChanges) {
-            const promises = [];
-
-            _.forEach(cacheStoreChanges, (change) =>
-                promises.push(mongo.Cache.update({_id: {$eq: change.cacheId}}, change.change, {}).exec())
-            );
-
-            return Promise.all(promises);
-        }
-
-        const _saveDomainModel = (domain, savedDomains) => {
-            const caches = domain.caches;
-            const cacheStoreChanges = domain.cacheStoreChanges;
-            const domainId = domain._id;
-
-            return mongo.DomainModel.findOne({space: domain.space, valueType: domain.valueType}).exec()
-                .then((_domain) => {
-                    if (_domain && domainId !== _domain._id.toString())
-                        throw new Error('Domain model with value type: "' + _domain.valueType + '" already exist.');
-
-                    if (domainId) {
-                        return mongo.DomainModel.update({_id: domain._id}, domain, {upsert: true}).exec()
-                            .then(() => mongo.Cache.update({_id: {$in: caches}}, {$addToSet: {domains: domainId}}, {multi: true}).exec())
-                            .then(() => mongo.Cache.update({_id: {$nin: caches}}, {$pull: {domains: domainId}}, {multi: true}).exec())
-                            .then(() => {
-                                savedDomains.push(domain);
-
-                                return _updateCacheStore(cacheStoreChanges);
-                            });
-                    }
-
-                    return (new mongo.DomainModel(domain)).save()
-                        .then((savedDomain) => {
-                            savedDomains.push(savedDomain);
-
-                            return mongo.Cache.update({_id: {$in: caches}}, {$addToSet: {domains: savedDomain._id}}, {multi: true}).exec();
-                        })
-                        .then(() => _updateCacheStore(cacheStoreChanges));
-                });
-        };
-
-        const _save = (domains, res) => {
-            if (domains && domains.length > 0) {
-                const savedDomains = [];
-                const generatedCaches = [];
-                const promises = [];
-
-                _.forEach(domains, (domain) => {
-                    if (domain.newCache) {
-                        promises.push(
-                            mongo.Cache.findOne({space: domain.space, name: domain.newCache.name}).exec()
-                                .then((cache) => {
-                                    if (cache)
-                                        return Promise.resolve(cache);
-
-                                    // If cache not found, then create it and associate with domain model.
-                                    const newCache = domain.newCache;
-                                    newCache.space = domain.space;
-
-                                    return (new mongo.Cache(newCache)).save()
-                                        .then((_cache) => {
-                                            generatedCaches.push(_cache);
-
-                                            return mongo.Cluster.update({_id: {$in: _cache.clusters}}, {$addToSet: {caches: _cache._id}}, {multi: true}).exec()
-                                                .then(() => Promise.resolve(_cache));
-                                        });
-                                })
-                                .then((cache) => {
-                                    domain.caches = [cache._id];
-
-                                    return _saveDomainModel(domain, savedDomains);
-                                })
-                                .catch((err) => mongo.handleError(res, err))
-                        );
-                    }
-                    else
-                        promises.push(_saveDomainModel(domain, savedDomains));
-                });
-
-                Promise.all(promises)
-                    .then(() => res.send({savedDomains, generatedCaches}))
-                    .catch((err) => mongo.handleError(res, err));
-            }
-            else
-                res.status(500).send('Nothing to save!');
-        };
-
-        /**
-         * Save domain model.
-         */
-        router.post('/save', (req, res) => {
-            _save([req.body], res);
-        });
-
-        /**
-         * Batch save domain models.
-         */
-        router.post('/save/batch', (req, res) => {
-            _save(req.body, res);
-        });
-
-        /**
-         * Remove domain model by ._id.
-         */
-        router.post('/remove', (req, res) => {
-            const params = req.body;
-            const domainId = params._id;
-
-            mongo.DomainModel.findOne(params).exec()
-                .then((domain) => mongo.Cache.update({_id: {$in: domain.caches}}, {$pull: {domains: domainId}}, {multi: true}).exec())
-                .then(() => mongo.DomainModel.remove(params).exec())
-                .then(() => res.sendStatus(200))
-                .catch((err) => mongo.handleError(res, err));
-        });
-
-        /**
-         * Remove all domain models.
-         */
-        router.post('/remove/all', (req, res) => {
-            mongo.spaceIds(req.currentUserId(), req.header('IgniteDemoMode'))
-                .then((spaceIds) => mongo.Cache.update({space: {$in: spaceIds}}, {domains: []}, {multi: true}).exec()
-                        .then(() => mongo.DomainModel.remove({space: {$in: spaceIds}}).exec()))
-                .then(() => res.sendStatus(200))
-                .catch((err) => mongo.handleError(res, err));
-        });
-
-        factoryResolve(router);
-    });
-};
-

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/src/main/js/serve/routes/igfs.js
----------------------------------------------------------------------
diff --git a/modules/web-console/src/main/js/serve/routes/igfs.js b/modules/web-console/src/main/js/serve/routes/igfs.js
deleted file mode 100644
index f590273..0000000
--- a/modules/web-console/src/main/js/serve/routes/igfs.js
+++ /dev/null
@@ -1,122 +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.
- */
-
-'use strict';
-
-// Fire me up!
-
-module.exports = {
-    implements: 'igfs-routes',
-    inject: ['require(lodash)', 'require(express)', 'mongo']
-};
-
-module.exports.factory = function(_, express, mongo) {
-    return new Promise((factoryResolve) => {
-        const router = new express.Router();
-
-        /**
-         * Get spaces and IGFSs accessed for user account.
-         *
-         * @param req Request.
-         * @param res Response.
-         */
-        router.post('/list', (req, res) => {
-            const result = {};
-            let spaceIds = [];
-
-            // Get owned space and all accessed space.
-            mongo.spaces(req.currentUserId(), req.header('IgniteDemoMode'))
-                .then((spaces) => {
-                    result.spaces = spaces;
-                    spaceIds = spaces.map((space) => space._id);
-
-                    return mongo.Cluster.find({space: {$in: spaceIds}}, '_id name').sort('name').lean().exec();
-                })
-                .then((clusters) => {
-                    result.clusters = clusters;
-
-                    return mongo.Igfs.find({space: {$in: spaceIds}}).sort('name').lean().exec();
-                })
-                .then((igfss) => {
-                    result.igfss = igfss;
-
-                    res.json(result);
-                })
-                .catch((err) => mongo.handleError(res, err));
-        });
-
-        /**
-         * Save IGFS.
-         */
-        router.post('/save', (req, res) => {
-            const params = req.body;
-            const clusters = params.clusters;
-
-            mongo.Igfs.findOne({space: params.space, name: params.name}).exec()
-                .then((_igfs) => {
-                    const igfsId = params._id;
-
-                    if (_igfs && igfsId !== _igfs._id.toString())
-                        return res.status(500).send('IGFS with name: "' + params.name + '" already exist.');
-
-                    if (params._id) {
-                        return mongo.Igfs.update({_id: igfsId}, params, {upsert: true}).exec()
-                            .then(() => mongo.Cluster.update({_id: {$in: clusters}}, {$addToSet: {igfss: igfsId}}, {multi: true}).exec())
-                            .then(() => mongo.Cluster.update({_id: {$nin: clusters}}, {$pull: {igfss: igfsId}}, {multi: true}).exec())
-                            .then(() => res.send(igfsId));
-                    }
-
-                    return (new mongo.Igfs(params)).save()
-                        .then((igfs) =>
-                            mongo.Cluster.update({_id: {$in: clusters}}, {$addToSet: {igfss: igfs._id}}, {multi: true}).exec()
-                                .then(() => res.send(igfs._id))
-                        );
-                })
-                .catch((err) => mongo.handleError(res, err));
-        });
-
-        /**
-         * Remove IGFS by ._id.
-         */
-        router.post('/remove', (req, res) => {
-            const params = req.body;
-            const igfsId = params._id;
-
-            mongo.Cluster.update({igfss: {$in: [igfsId]}}, {$pull: {igfss: igfsId}}, {multi: true}).exec()
-                .then(() => mongo.Igfs.remove(params).exec())
-                .then(() => res.sendStatus(200))
-                .catch((err) => mongo.handleError(res, err));
-        });
-
-        /**
-         * Remove all IGFSs.
-         */
-        router.post('/remove/all', (req, res) => {
-            // Get owned space and all accessed space.
-            mongo.spaceIds(req.currentUserId(), req.header('IgniteDemoMode'))
-                .then((spaceIds) =>
-                    mongo.Cluster.update({space: {$in: spaceIds}}, {igfss: []}, {multi: true}).exec()
-                        .then(() => mongo.Igfs.remove({space: {$in: spaceIds}}).exec())
-                )
-                .then(() => res.sendStatus(200))
-                .catch((err) => mongo.handleError(res, err));
-        });
-
-        factoryResolve(router);
-    });
-};
-

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/src/main/js/serve/routes/notebooks.js
----------------------------------------------------------------------
diff --git a/modules/web-console/src/main/js/serve/routes/notebooks.js b/modules/web-console/src/main/js/serve/routes/notebooks.js
deleted file mode 100644
index 37665bf..0000000
--- a/modules/web-console/src/main/js/serve/routes/notebooks.js
+++ /dev/null
@@ -1,121 +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.
- */
-
-'use strict';
-
-// Fire me up!
-
-module.exports = {
-    implements: 'notebooks-routes',
-    inject: ['require(express)', 'mongo']
-};
-
-module.exports.factory = function(express, mongo) {
-    return new Promise((factoryResolve) => {
-        const router = new express.Router();
-
-        /**
-         * Get notebooks names accessed for user account.
-         *
-         * @param req Request.
-         * @param res Response.
-         */
-        router.post('/list', (req, res) => {
-            mongo.spaces(req.currentUserId())
-                .then((spaces) => mongo.Notebook.find({space: {$in: spaces.map((value) => value._id)}}).select('_id name').sort('name').lean().exec())
-                .then((notebooks) => res.json(notebooks))
-                .catch((err) => mongo.handleError(res, err));
-
-        });
-
-        /**
-         * Get notebook accessed for user account.
-         *
-         * @param req Request.
-         * @param res Response.
-         */
-        router.post('/get', (req, res) => {
-            mongo.spaces(req.currentUserId())
-                .then((spaces) => mongo.Notebook.findOne({space: {$in: spaces.map((value) => value._id)}, _id: req.body.noteId}).lean().exec())
-                .then((notebook) => res.json(notebook))
-                .catch((err) => mongo.handleError(res, err));
-        });
-
-        /**
-         * Save notebook accessed for user account.
-         *
-         * @param req Request.
-         * @param res Response.
-         */
-        router.post('/save', (req, res) => {
-            const note = req.body;
-
-            mongo.Notebook.findOne({space: note.space, name: note.name}).exec()
-                .then((notebook) => {
-                    const noteId = note._id;
-
-                    if (notebook && noteId !== notebook._id.toString())
-                        throw new Error('Notebook with name: "' + notebook.name + '" already exist.');
-
-                    if (noteId) {
-                        return mongo.Notebook.update({_id: noteId}, note, {upsert: true}).exec()
-                            .then(() => res.send(noteId))
-                            .catch((err) => mongo.handleError(res, err));
-                    }
-
-                    return (new mongo.Notebook(req.body)).save();
-                })
-                .then((notebook) => res.send(notebook._id))
-                .catch((err) => mongo.handleError(res, err));
-        });
-
-        /**
-         * Remove notebook by ._id.
-         *
-         * @param req Request.
-         * @param res Response.
-         */
-        router.post('/remove', (req, res) => {
-            mongo.Notebook.remove(req.body).exec()
-                .then(() => res.sendStatus(200))
-                .catch((err) => mongo.handleError(res, err));
-        });
-
-        /**
-         * Create new notebook for user account.
-         *
-         * @param req Request.
-         * @param res Response.
-         */
-        router.post('/new', (req, res) => {
-            mongo.spaceIds(req.currentUserId())
-                .then((spaceIds) =>
-                    mongo.Notebook.findOne({space: spaceIds[0], name: req.body.name})
-                        .then((notebook) => {
-                            if (notebook)
-                                throw new Error('Notebook with name: "' + notebook.name + '" already exist.');
-
-                            return spaceIds;
-                        }))
-                .then((spaceIds) => (new mongo.Notebook({space: spaceIds[0], name: req.body.name})).save())
-                .then((notebook) => res.send(notebook._id))
-                .catch((err) => mongo.handleError(res, err));
-        });
-
-        factoryResolve(router);
-    });
-};

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/src/main/js/serve/routes/profile.js
----------------------------------------------------------------------
diff --git a/modules/web-console/src/main/js/serve/routes/profile.js b/modules/web-console/src/main/js/serve/routes/profile.js
deleted file mode 100644
index 5563a2b..0000000
--- a/modules/web-console/src/main/js/serve/routes/profile.js
+++ /dev/null
@@ -1,102 +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.
- */
-
-'use strict';
-
-// Fire me up!
-
-module.exports = {
-    implements: 'profile-routes',
-    inject: ['require(lodash)', 'require(express)', 'mongo', 'agent-manager']
-};
-
-/**
- *
- * @param _ Lodash module
- * @param express Express module
- * @param mongo
- * @param {AgentManager} agentMgr
- * @returns {Promise}
- */
-module.exports.factory = function(_, express, mongo, agentMgr) {
-    return new Promise((resolveFactory) => {
-        const router = new express.Router();
-
-        /**
-         * Save user profile.
-         */
-        router.post('/save', (req, res) => {
-            const params = req.body;
-
-            if (params.password && _.isEmpty(params.password))
-                return res.status(500).send('Wrong value for new password!');
-
-            mongo.Account.findById(params._id).exec()
-                .then((user) => {
-                    if (!params.password)
-                        return Promise.resolve(user);
-
-                    return new Promise((resolve, reject) => {
-                        user.setPassword(params.password, (err, _user) => {
-                            if (err)
-                                return reject(err);
-
-                            delete params.password;
-
-                            resolve(_user);
-                        });
-                    });
-                })
-                .then((user) => {
-                    if (!params.email || user.email === params.email)
-                        return Promise.resolve(user);
-
-                    return new Promise((resolve, reject) => {
-                        mongo.Account.findOne({email: params.email}, (err, _user) => {
-                            // TODO send error to admin
-                            if (err)
-                                reject(new Error('Failed to check email!'));
-
-                            if (_user && _user._id !== user._id)
-                                reject(new Error('User with this email already registered!'));
-
-                            resolve(user);
-                        });
-                    });
-                })
-                .then((user) => {
-                    if (params.token && user.token !== params.token)
-                        agentMgr.close(user._id, user.token);
-
-                    _.extend(user, params);
-
-                    return user.save();
-                })
-                .then((user) => {
-                    const becomeUsed = req.session.viewedUser && req.user.admin;
-
-                    if (becomeUsed)
-                        req.session.viewedUser = user;
-
-                    res.sendStatus(200);
-                })
-                .catch((err) => mongo.handleError(res, err));
-        });
-
-        resolveFactory(router);
-    });
-};

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/src/main/js/serve/routes/public.js
----------------------------------------------------------------------
diff --git a/modules/web-console/src/main/js/serve/routes/public.js b/modules/web-console/src/main/js/serve/routes/public.js
deleted file mode 100644
index 207289a..0000000
--- a/modules/web-console/src/main/js/serve/routes/public.js
+++ /dev/null
@@ -1,235 +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.
- */
-
-'use strict';
-
-// Fire me up!
-
-module.exports = {
-    implements: 'public-routes',
-    inject: ['require(express)', 'require(passport)', 'require(nodemailer)', 'settings', 'mail', 'mongo']
-};
-
-module.exports.factory = function(express, passport, nodemailer, settings, mail, mongo) {
-    return new Promise((factoryResolve) => {
-        const router = new express.Router();
-
-        const _randomString = () => {
-            const possible = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';
-            const possibleLen = possible.length;
-
-            let res = '';
-
-            for (let i = 0; i < settings.tokenLength; i++)
-                res += possible.charAt(Math.floor(Math.random() * possibleLen));
-
-            return res;
-        };
-
-        // GET user.
-        router.post('/user', (req, res) => {
-            const becomeUsed = req.session.viewedUser && req.user.admin;
-
-            let user = req.user;
-
-            if (becomeUsed) {
-                user = req.session.viewedUser;
-
-                user.becomeUsed = true;
-            }
-            else if (user)
-                user = user.toJSON();
-            else
-                return res.json(user);
-
-            mongo.Space.findOne({owner: user._id, demo: true}).exec()
-                .then((demoSpace) => {
-                    if (user && demoSpace)
-                        user.demoCreated = true;
-
-                    res.json(user);
-                })
-                .catch((err) => {
-                    res.status(401).send(err.message);
-                });
-        });
-
-        /**
-         * Register new account.
-         */
-        router.post('/signup', (req, res) => {
-            mongo.Account.count().exec()
-                .then((cnt) => {
-                    req.body.admin = cnt === 0;
-
-                    req.body.token = _randomString();
-
-                    return new mongo.Account(req.body);
-                })
-                .then((account) => {
-                    return new Promise((resolve, reject) => {
-                        mongo.Account.register(account, req.body.password, (err, _account) => {
-                            if (err)
-                                reject(err);
-
-                            if (!_account)
-                                reject(new Error('Failed to create account.'));
-
-                            resolve(_account);
-                        });
-                    });
-                })
-                .then((account) => new mongo.Space({name: 'Personal space', owner: account._id}).save()
-                    .then(() => account)
-                )
-                .then((account) => {
-                    return new Promise((resolve, reject) => {
-                        req.logIn(account, {}, (err) => {
-                            if (err)
-                                reject(err);
-
-                            resolve(account);
-                        });
-                    });
-                })
-                .then((account) => {
-                    res.sendStatus(200);
-
-                    account.resetPasswordToken = _randomString();
-
-                    return account.save()
-                        .then(() => {
-                            const resetLink = `http://${req.headers.host}/password/reset?token=${account.resetPasswordToken}`;
-
-                            mail.send(account, `Thanks for signing up for ${settings.smtp.username}.`,
-                                `Hello ${account.firstName} ${account.lastName}!<br><br>` +
-                                `You are receiving this email because you have signed up to use <a href="http://${req.headers.host}">${settings.smtp.username}</a>.<br><br>` +
-                                'If you have not done the sign up and do not know what this email is about, please ignore it.<br>' +
-                                'You may reset the password by clicking on the following link, or paste this into your browser:<br><br>' +
-                                `<a href="${resetLink}">${resetLink}</a>`);
-                        });
-                })
-                .catch((err) => {
-                    res.status(401).send(err.message);
-                });
-        });
-
-        /**
-         * Sign in into exist account.
-         */
-        router.post('/signin', (req, res, next) => {
-            passport.authenticate('local', (errAuth, user) => {
-                if (errAuth)
-                    return res.status(401).send(errAuth.message);
-
-                if (!user)
-                    return res.status(401).send('Invalid email or password');
-
-                req.logIn(user, {}, (errLogIn) => {
-                    if (errLogIn)
-                        return res.status(401).send(errLogIn.message);
-
-                    return res.sendStatus(200);
-                });
-            })(req, res, next);
-        });
-
-        /**
-         * Logout.
-         */
-        router.post('/logout', (req, res) => {
-            req.logout();
-
-            res.sendStatus(200);
-        });
-
-        /**
-         * Send e-mail to user with reset token.
-         */
-        router.post('/password/forgot', (req, res) => {
-            mongo.Account.findOne({email: req.body.email}).exec()
-                .then((user) => {
-                    if (!user)
-                        throw new Error('Account with that email address does not exists!');
-
-                    user.resetPasswordToken = _randomString();
-
-                    return user.save();
-                })
-                .then((user) => {
-                    const resetLink = `http://${req.headers.host}/password/reset?token=${user.resetPasswordToken}`;
-
-                    mail.send(user, 'Password Reset',
-                        `Hello ${user.firstName} ${user.lastName}!<br><br>` +
-                        'You are receiving this because you (or someone else) have requested the reset of the password for your account.<br><br>' +
-                        'Please click on the following link, or paste this into your browser to complete the process:<br><br>' +
-                        `<a href="${resetLink}">${resetLink}</a><br><br>` +
-                        'If you did not request this, please ignore this email and your password will remain unchanged.',
-                        'Failed to send email with reset link!');
-                })
-                .then(() => res.status(200).send('An email has been sent with further instructions.'))
-                .catch((err) => {
-                    // TODO IGNITE-843 Send email to admin
-                    return res.status(401).send(err.message);
-                });
-        });
-
-        /**
-         * Change password with given token.
-         */
-        router.post('/password/reset', (req, res) => {
-            mongo.Account.findOne({resetPasswordToken: req.body.token}).exec()
-                .then((user) => {
-                    if (!user)
-                        throw new Error('Failed to find account with this token! Please check link from email.');
-
-                    return new Promise((resolve, reject) => {
-                        user.setPassword(req.body.password, (err, _user) => {
-                            if (err)
-                                return reject(new Error('Failed to reset password: ' + err.message));
-
-                            _user.resetPasswordToken = undefined; // eslint-disable-line no-undefined
-
-                            resolve(_user.save());
-                        });
-                    });
-                })
-                .then((user) => mail.send(user, 'Your password has been changed',
-                    `Hello ${user.firstName} ${user.lastName}!<br><br>` +
-                    `This is a confirmation that the password for your account on <a href="http://${req.headers.host}">${settings.smtp.username}</a> has just been changed.<br><br>`,
-                    'Password was changed, but failed to send confirmation email!'))
-                .then((user) => res.status(200).send(user.email))
-                .catch((err) => res.status(401).send(err.message));
-        });
-
-        /* GET reset password page. */
-        router.post('/password/validate/token', (req, res) => {
-            const token = req.body.token;
-
-            mongo.Account.findOne({resetPasswordToken: token}).exec()
-                .then((user) => {
-                    if (!user)
-                        throw new Error('Invalid token for password reset!');
-
-                    return res.json({token, email: user.email});
-                })
-                .catch((err) => res.status(401).send(err.message));
-        });
-
-        factoryResolve(router);
-    });
-};

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/src/main/js/serve/routes/routes.js
----------------------------------------------------------------------
diff --git a/modules/web-console/src/main/js/serve/routes/routes.js b/modules/web-console/src/main/js/serve/routes/routes.js
deleted file mode 100644
index cbee8bb..0000000
--- a/modules/web-console/src/main/js/serve/routes/routes.js
+++ /dev/null
@@ -1,103 +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.
- */
-
-'use strict';
-
-// Fire me up!
-
-module.exports = {
-    implements: 'routes',
-    inject: [
-        'public-routes',
-        'admin-routes',
-        'profile-routes',
-        'demo-routes',
-        'clusters-routes',
-        'domains-routes',
-        'caches-routes',
-        'igfs-routes',
-        'notebooks-routes',
-        'agent-routes',
-        'ignite_modules/routes:*' // Loads all routes modules of all plugins
-    ]
-};
-
-module.exports.factory = function(publicRoutes, adminRoutes, profileRoutes, demoRoutes,
-    clusterRoutes, domainRoutes, cacheRoutes, igfsRoutes, notebookRoutes, agentRoutes, pluginRoutes) {
-    return {
-        register: (app) => {
-            app.all('*', (req, res, next) => {
-                req.currentUserId = () => {
-                    if (!req.user)
-                        return null;
-
-                    if (req.session.viewedUser && req.user.admin)
-                        return req.session.viewedUser._id;
-
-                    return req.user._id;
-                };
-
-                next();
-            });
-
-            const _mustAuthenticated = (req, res, next) => req.isAuthenticated() ? next() : res.redirect('/');
-
-            const _adminOnly = (req, res, next) => req.isAuthenticated() && req.user.admin ? next() : res.sendStatus(403);
-
-            // Registering the standard routes
-            app.use('/', publicRoutes);
-            app.use('/admin', _mustAuthenticated, _adminOnly, adminRoutes);
-            app.use('/profile', _mustAuthenticated, profileRoutes);
-            app.use('/demo', _mustAuthenticated, demoRoutes);
-
-            app.all('/configuration/*', _mustAuthenticated);
-
-            app.use('/configuration/clusters', clusterRoutes);
-            app.use('/configuration/domains', domainRoutes);
-            app.use('/configuration/caches', cacheRoutes);
-            app.use('/configuration/igfs', igfsRoutes);
-
-            app.use('/notebooks', _mustAuthenticated, notebookRoutes);
-            app.use('/agent', _mustAuthenticated, agentRoutes);
-
-            // Registering the routes of all plugin modules
-            for (const name in pluginRoutes) {
-                if (pluginRoutes.hasOwnProperty(name))
-                    pluginRoutes[name].register(app, _mustAuthenticated, _adminOnly);
-            }
-
-            // Catch 404 and forward to error handler.
-            app.use((req, res, next) => {
-                const err = new Error('Not Found: ' + req.originalUrl);
-
-                err.status = 404;
-
-                next(err);
-            });
-
-            // Production error handler: no stacktraces leaked to user.
-            app.use((err, req, res) => {
-                res.status(err.status || 500);
-
-                res.render('error', {
-                    message: err.message,
-                    error: {}
-                });
-            });
-        }
-    };
-};

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/src/main/js/serve/settings.js
----------------------------------------------------------------------
diff --git a/modules/web-console/src/main/js/serve/settings.js b/modules/web-console/src/main/js/serve/settings.js
deleted file mode 100644
index 5b14bcc..0000000
--- a/modules/web-console/src/main/js/serve/settings.js
+++ /dev/null
@@ -1,84 +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.
- */
-
-'use strict';
-
-// Fire me up!
-
-/**
- * Module with server-side configuration.
- */
-module.exports = {
-    implements: 'settings',
-    inject: ['require(nconf)', 'require(fs)']
-};
-
-module.exports.factory = function(nconf, fs) {
-    nconf.file({file: './serve/config/settings.json'});
-
-    /**
-     * Normalize a port into a number, string, or false.
-     */
-    const _normalizePort = function(val) {
-        const port = parseInt(val, 10);
-
-        // named pipe
-        if (isNaN(port))
-            return val;
-
-        // port number
-        if (port >= 0)
-            return port;
-
-        return false;
-    };
-
-    return {
-        agent: {
-            dists: 'serve/agent_dists',
-            port: _normalizePort(nconf.get('agent-server:port') || 3002),
-            legacyPort: _normalizePort(nconf.get('agent-server:legacyPort')),
-            SSLOptions: nconf.get('agent-server:ssl') && {
-                key: fs.readFileSync(nconf.get('agent-server:key')),
-                cert: fs.readFileSync(nconf.get('agent-server:cert')),
-                passphrase: nconf.get('agent-server:keyPassphrase')
-            }
-        },
-        server: {
-            port: _normalizePort(nconf.get('server:port') || 3000),
-            SSLOptions: nconf.get('server:ssl') && {
-                enable301Redirects: true,
-                trustXFPHeader: true,
-                key: fs.readFileSync(nconf.get('server:key')),
-                cert: fs.readFileSync(nconf.get('server:cert')),
-                passphrase: nconf.get('server:keyPassphrase')
-            }
-        },
-        smtp: {
-            service: nconf.get('smtp:service'),
-            username: nconf.get('smtp:username'),
-            sign: nconf.get('smtp:sign'),
-            email: nconf.get('smtp:email'),
-            password: nconf.get('smtp:password'),
-            address: (username, email) => username ? '"' + username + '" <' + email + '>' : email
-        },
-        mongoUrl: nconf.get('mongoDB:url') || 'mongodb://localhost/console',
-        cookieTTL: 3600000 * 24 * 30,
-        sessionSecret: 'keyboard cat',
-        tokenLength: 20
-    };
-};

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/src/main/js/views/base.jade
----------------------------------------------------------------------
diff --git a/modules/web-console/src/main/js/views/base.jade b/modules/web-console/src/main/js/views/base.jade
deleted file mode 100644
index a910d1b..0000000
--- a/modules/web-console/src/main/js/views/base.jade
+++ /dev/null
@@ -1,22 +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.
-
-include includes/header
-
-.container.body-container
-    .main-content(ui-view='')
-
-include includes/footer

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/src/main/js/views/configuration/caches.jade
----------------------------------------------------------------------
diff --git a/modules/web-console/src/main/js/views/configuration/caches.jade b/modules/web-console/src/main/js/views/configuration/caches.jade
deleted file mode 100644
index a5b331f..0000000
--- a/modules/web-console/src/main/js/views/configuration/caches.jade
+++ /dev/null
@@ -1,52 +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.
-
-include ../../app/helpers/jade/mixins.jade
-
-.docs-header
-    h1 Configure Ignite Caches
-.docs-body(ng-controller='cachesController')
-    ignite-information
-        ul
-            li Configure #[a(href='https://apacheignite.readme.io/docs/data-grid' target='_blank') memory] settings
-            li Configure persistence
-    div(ignite-loading='loadingCachesScreen' ignite-loading-text='Loading caches...' ignite-loading-position='top')
-        div(ng-show='ui.ready')
-            hr
-            +main-table('caches', 'caches', 'cacheName', 'selectItem(row)', '{{$index + 1}}) {{row.label}}', 'label')
-            .padding-top-dflt(bs-affix)
-                .panel-tip-container(data-placement='bottom' bs-tooltip='' data-title='Create new cache')
-                    button.btn.btn-primary(id='new-item' ng-click='createItem()') Add cache
-                +save-remove-clone-undo-buttons('cache')
-                hr
-            .bs-affix-fix
-            div(bs-collapse='' data-allow-multiple='true' ng-model='ui.activePanels')
-                form.form-horizontal(name='ui.inputForm' ng-show='contentVisible()' novalidate)
-                    .panel-group
-                        ignite-configuration-caches-general
-                        ignite-configuration-caches-memory
-                        ignite-configuration-caches-query
-                        ignite-configuration-caches-store
-
-                        +advanced-options-toggle-default
-
-                        div(ng-show='ui.expanded')
-                            ignite-configuration-caches-concurrency
-                            ignite-configuration-caches-rebalance
-                            ignite-configuration-caches-server-near-cache
-                            ignite-configuration-caches-statistics
-
-                            +advanced-options-toggle-default

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/src/main/js/views/configuration/clusters.jade
----------------------------------------------------------------------
diff --git a/modules/web-console/src/main/js/views/configuration/clusters.jade b/modules/web-console/src/main/js/views/configuration/clusters.jade
deleted file mode 100644
index 6450163..0000000
--- a/modules/web-console/src/main/js/views/configuration/clusters.jade
+++ /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.
-
-include ../../app/helpers/jade/mixins.jade
-
-.docs-header
-    h1 Configure Ignite Clusters
-.docs-body(ng-controller='clustersController')
-    ignite-information
-        ul
-            li Configure #[a(href='https://apacheignite.readme.io/docs/clustering' target='_blank') clusters] properties
-            li Associate clusters with caches and in-memory file systems
-    div(ignite-loading='loadingClustersScreen' ignite-loading-text='Loading clusters...' ignite-loading-position='top')
-        div(ng-show='ui.ready')
-            hr
-            +main-table('clusters', 'clusters', 'clusterName', 'selectItem(row)', '{{$index + 1}}) {{row.label}}', 'label')
-            .padding-top-dflt(bs-affix)
-                .panel-tip-container(data-placement='bottom' bs-tooltip='' data-title='Create new cluster')
-                    button.btn.btn-primary(id='new-item' ng-click='createItem()') Add cluster
-                +save-remove-clone-undo-buttons('cluster')
-                hr
-            .bs-affix-fix
-            div(bs-collapse='' data-allow-multiple='true' ng-model='ui.activePanels')
-                form.form-horizontal(name='ui.inputForm' ng-show='contentVisible()' novalidate)
-                    .panel-group
-                        ignite-configuration-clusters-general
-
-                        +advanced-options-toggle-default
-
-                        div(ng-show='ui.expanded')
-                            ignite-configuration-clusters-atomic
-                            ignite-configuration-clusters-binary
-                            ignite-configuration-clusters-collision
-                            ignite-configuration-clusters-communication
-                            ignite-configuration-clusters-connector
-                            ignite-configuration-clusters-deployment
-                            ignite-configuration-clusters-discovery
-                            ignite-configuration-clusters-events
-                            ignite-configuration-clusters-failover
-                            ignite-configuration-clusters-igfs
-                            ignite-configuration-clusters-logger
-                            ignite-configuration-clusters-marshaller
-                            ignite-configuration-clusters-metrics
-                            ignite-configuration-clusters-ssl
-                            ignite-configuration-clusters-swap
-                            ignite-configuration-clusters-thread
-                            ignite-configuration-clusters-time
-                            ignite-configuration-clusters-transactions
-                            ignite-configuration-user-attributes
-
-                            +advanced-options-toggle-default

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/src/main/js/views/configuration/domains-import.jade
----------------------------------------------------------------------
diff --git a/modules/web-console/src/main/js/views/configuration/domains-import.jade b/modules/web-console/src/main/js/views/configuration/domains-import.jade
deleted file mode 100644
index ccaeb27..0000000
--- a/modules/web-console/src/main/js/views/configuration/domains-import.jade
+++ /dev/null
@@ -1,211 +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.
-
-include ../../app/helpers/jade/mixins.jade
-
-mixin chk(mdl, change, tip)
-    input(type='checkbox' ng-model=mdl ng-change=change bs-tooltip='' data-title=tip data-trigger='hover' data-placement='top')
-
-mixin td-ellipses-lbl(w, lbl)
-    td.td-ellipsis(width='#{w}' style='min-width: #{w}; max-width: #{w}')
-        label #{lbl}
-
-.modal.modal-domain-import.center(role='dialog')
-    .modal-dialog.domains-import-dialog
-        .modal-content(ignite-loading='importDomainFromDb' ignite-loading-text='{{importDomain.loadingOptions.text}}')
-            #errors-container.modal-header.header
-                button.close(ng-click='$hide()' aria-hidden='true') &times;
-                h4.modal-title(ng-if='!importDomain.demo') Import domain models from database
-                h4.modal-title(ng-if='importDomain.demo') Import domain models from demo database
-            .modal-body
-                .import-domain-model-wizard-page(ng-if='importDomain.action == "drivers" && !importDomain.jdbcDriversNotFound')
-                .import-domain-model-wizard-page(ng-if='importDomain.action == "drivers" && importDomain.jdbcDriversNotFound')
-                    | Domain model could not be imported
-                    ul
-                        li Agent failed to find JDBC drivers
-                        li Copy required JDBC drivers into agent 'jdbc-drivers' folder and try again
-                        li Refer to agent README.txt for more information
-                .import-domain-model-wizard-page(ng-show='importDomain.action == "connect" && importDomain.demo')
-                    div(ng-if='demoConnection.db == "H2"')
-                        label Demo description:
-                        ul
-                            li In-memory H2 database server will be started inside agent
-                            li Database will be populated with sample tables
-                            li You could test domain model generation with this demo database
-                            li Click "Next" to continue
-                    div(ng-if='demoConnection.db != "H2"')
-                        label Demo could not be started
-                            ul
-                                li Agent failed to resolve H2 database jar
-                                li Copy h2-x.x.x.jar into agent 'jdbc-drivers' folder and try again
-                                li Refer to agent README.txt for more information
-                .import-domain-model-wizard-page(ng-show='importDomain.action == "connect" && !importDomain.demo')
-                    form.form-horizontal(name='connectForm' novalidate)
-                        .settings-row
-                            label.col-xs-4.col-sm-2.col-md-2 Driver JAR:
-                            .col-xs-8.col-sm-10.col-md-10
-                                i.tipField.fa.fa-question-circle(bs-tooltip='' data-title='Select appropriate JAR with JDBC driver<br> To add another driver you need to place it into "/jdbc-drivers" folder of Ignite Web Agent<br> Refer to Ignite Web Agent README.txt for for more information')
-                                .input-tip
-                                    button.select-toggle.form-control(id='jdbcDriverJar' bs-select data-container='.modal-domain-import' ng-model='ui.selectedJdbcDriverJar' ng-class='{placeholder: !(jdbcDriverJars && jdbcDriverJars.length > 0)}' placeholder='Choose JDBC driver' bs-options='item.value as item.label for item in jdbcDriverJars')
-                        .settings-row
-                            label.col-xs-4.col-sm-2.col-md-2 JDBC Driver:
-                            .col-xs-8.col-sm-10.col-md-10
-                                i.tipField.fa.fa-question-circle(bs-tooltip='' data-title='Fully qualified class name of JDBC driver that will be used to connect to database')
-                                .input-tip
-                                    input.form-control(id='jdbcDriverClass' type='text' ng-model='selectedPreset.jdbcDriverClass' placeholder='JDBC driver fully qualified class name' required=true)
-                        .settings-row
-                            label.col-xs-4.col-sm-2.col-md-2 JDBC URL:
-                            .col-xs-8.col-sm-10.col-md-10
-                                i.tipField.fa.fa-question-circle(bs-tooltip='' data-title='JDBC URL for connecting to database<br>Refer to your database documentation for details')
-                                .input-tip
-                                    input.form-control(id='jdbcUrl' type='text' ng-model='selectedPreset.jdbcUrl' placeholder='JDBC URL' required=true)
-                        .settings-row
-                            label.col-xs-4.col-sm-2.col-md-2 User:
-                            .col-xs-8.col-sm-10.col-md-10
-                                i.tipField.fa.fa-question-circle(bs-tooltip='' data-title='User name for connecting to database')
-                                .input-tip
-                                    input.form-control(id='user' type='text' ng-model='selectedPreset.user')
-                        .settings-row
-                            label.col-xs-4.col-sm-2.col-md-2 Password:
-                            .col-xs-8.col-sm-10.col-md-10
-                                i.tipField.fa.fa-question-circle(bs-tooltip='' data-title='Password for connecting to database<br>Note, password would not be saved in preferences for security reasons')
-                                .input-tip
-                                    input.form-control(id='password' type='password' ng-model='selectedPreset.password' ignite-on-enter='importDomainNext()')
-                        .settings-row
-                            .checkbox
-                                label
-                                    input(id='tablesOnly' type='checkbox' ng-model='selectedPreset.tablesOnly')
-                                    | Tables only
-                                i.tipLabel.fa.fa-question-circle(bs-tooltip='' data-title='If selected, then only tables metadata will be parsed<br>Otherwise table and view metadata will be parsed')
-                .import-domain-model-wizard-page(ng-show='importDomain.action == "schemas"')
-                    table.table.metadata(st-table='importDomain.displayedSchemas' st-safe-src='importDomain.schemas')
-                        thead
-                            tr
-                                th.header(colspan='2')
-                                    .col-sm-4.pull-right(style='margin-bottom: 5px')
-                                        input.form-control(type='text' st-search='name' placeholder='Filter schemas...' ng-model='importDomain.displayedSchemasFilter' ng-change='selectSchema()')
-                            tr
-                                th(width='30px')
-                                    +chk('importDomain.allSchemasSelected',  'selectAllSchemas()', 'Select all schemas')
-                                th
-                                    label Schema
-                            tbody
-                                tr
-                                    td(colspan='2')
-                                        .scrollable-y(style='height: 213px')
-                                            table.table-modal-striped(id='importSchemasData')
-                                                tbody
-                                                    tr(ng-repeat='schema in importDomain.displayedSchemas')
-                                                        td(width='30px')
-                                                            input(type='checkbox' ng-model='schema.use' ng-change='selectSchema()')
-                                                        td
-                                                            label {{schema.name}}
-                .import-domain-model-wizard-page(ng-show='importDomain.action == "tables"')
-                    table.table.metadata(st-table='importDomain.displayedTables' st-safe-src='importDomain.tables')
-                        thead
-                            tr
-                                th.header(colspan='6')
-                                    .col-sm-4.pull-right(style='margin-bottom: 8px')
-                                        input.form-control(type='text' st-search='label' placeholder='Filter tables...' ng-model='importDomain.displayedTablesFilter' ng-change='selectTable()')
-                            tr
-                                th(width='30px')
-                                    +chk('importDomain.allTablesSelected',  'selectAllTables()', 'Select all tables')
-                                th(width='130px')
-                                    label Schema
-                                th(width='160px')
-                                    label Table name
-                                th(colspan=2 width='288px')
-                                    label Cache
-                                th
-                        tbody
-                            tr
-                                td(colspan='6')
-                                    .scrollable-y(style='height: 143px')
-                                        table.table-modal-striped(id='importTableData')
-                                            tbody
-                                                tr(ng-repeat='table in importDomain.displayedTables track by $index')
-                                                    td(width='30px' style='min-width: 30px; max-width: 30px')
-                                                        input(type='checkbox' ng-model='table.use' ng-change='selectTable()')
-                                                    +td-ellipses-lbl('130px', '{{table.schema}}')
-                                                    +td-ellipses-lbl('160px', '{{table.tbl}}')
-                                                    td(colspan='2' width='288px' style='min-width: 160px; max-width: 160px')
-                                                        div.td-ellipsis
-                                                            a(ng-if='!table.edit' ng-click='startEditDbTableCache(table)') {{tableActionView(table)}}
-                                                            div(style='display: flex' ng-if='table.edit')
-                                                                button.select-toggle.form-control(style='width: 35%; margin-right: 5px' bs-select ng-model='table.action' data-container='.modal-domain-import' bs-options='item.value as item.shortLabel for item in importActions')
-                                                                button.select-toggle.form-control(style='width: 65%; margin-right: 0' bs-select ng-model='table.cacheOrTemplate' data-container='.modal-domain-import' bs-options='item.value as item.label for item in table.cachesOrTemplates')
-                                                    td
-                    .settings-row
-                        label Defaults to be applied for filtered tables
-                        i.tipLabel.fa.fa-question-circle(bs-tooltip='' data-title='Select and apply options for caches generation')
-                    .settings-row
-                        .col-sm-11
-                            .col-sm-6(style='padding-right: 5px')
-                                button.select-toggle.form-control(bs-select ng-model='importCommon.action' data-container='.modal-domain-import' bs-options='item.value as item.label for item in importActions')
-                            .col-sm-6(style='padding-left: 5px; padding-right: 5px')
-                                button.select-toggle.form-control(bs-select ng-model='importCommon.cacheOrTemplate' data-container='.modal-domain-import' bs-options='item.value as item.label for item in importCommon.cachesOrTemplates')
-                        .col-sm-1(style='padding-left: 5px')
-                            button.btn.btn-primary(ng-click='applyDefaults()') Apply
-                .import-domain-model-wizard-page(ng-show='importDomain.action == "options"')
-                    form.form-horizontal(name='optionsForm' novalidate)
-                        .settings-row
-                            .col-xs-3.col-sm-2.col-md-2.required
-                                label.required Package:
-                            .col-xs-9.col-sm-10.col-md-10
-                                i.tipField.fa.fa-question-circle(bs-tooltip='' data-title='Package that will be used for POJOs generation')
-                                .input-tip
-                                    ignite-form-field-input-text(
-                                        data-id='domainPackageName'
-                                        data-name='domainPackageName'
-                                        data-ng-model='ui.packageName'
-                                        data-ignite-label-name='Package'
-                                        data-ng-required='true'
-                                        data-placeholder='Enter package name'
-                                        data-java-keywords='true'
-                                        data-java-package-name='package-only'
-                                        ng-model-options='{allowInvalid: true}'
-                                    )
-                                        +error-feedback('optionsForm.$error.javaPackageName', 'javaPackageName', 'Package name is invalid')
-                                        +error-feedback('optionsForm.$error.javaKeywords', 'javaKeywords', 'Package name could not contains reserved java keyword')
-                        .settings-row
-                            .checkbox
-                                label
-                                    input(id='domainBuiltinKeys' type='checkbox' ng-model='ui.builtinKeys')
-                                    | Use Java built-in types for keys
-                                    i.tipLabel.fa.fa-question-circle(bs-tooltip='' data-title='Use Java built-in types like "Integer", "Long", "String" instead of POJO generation in case when table primary key contains only one field')
-                        .settings-row
-                            .checkbox
-                                label
-                                    input(id='domainUsePrimitives' type='checkbox' ng-model='ui.usePrimitives')
-                                    | Use primitive types for NOT NULL table columns
-                                    i.tipLabel.fa.fa-question-circle(bs-tooltip='' data-title='Use primitive types like "int", "long", "double" for POJOs fields generation in case of NOT NULL columns')
-                        .settings-row
-                            .checkbox
-                                label
-                                    input(id='domainGenerateAliases' type='checkbox' ng-model='ui.generateAliases')
-                                    | Generate aliases for query fields
-                                    i.tipLabel.fa.fa-question-circle(bs-tooltip='' data-title='Generate aliases for query fields with names from database fields')
-                        .settings-row
-                            .col-xs-3.col-sm-2.col-md-2.required
-                                label Clusters:
-                            .col-xs-9.col-sm-10.col-md-10
-                                i.tipField.fa.fa-question-circle(bs-tooltip='' data-title='Choose clusters that will be associated with generated caches')
-                                .input-tip
-                                    button.select-toggle.form-control(id='generatedCachesClusters' bs-select ng-model='ui.generatedCachesClusters' ng-class='{placeholder: !(ui.generatedCachesClusters && ui.generatedCachesClusters.length > 0)}' data-container='.modal-domain-import' data-multiple='1' placeholder='Choose clusters for generated caches' bs-options='item.value as item.label for item in clusters')
-            .modal-footer
-                label(ng-hide='importDomain.action == "drivers" || (importDomain.action == "connect" && importDomain.demo)').labelField {{importDomain.info}}
-                a.btn.btn-primary(ng-hide='importDomain.action == "drivers" || importDomain.action == "connect"' ng-click='importDomainPrev()' bs-tooltip='' data-title='{{prevTooltipText()}}' data-placement='bottom') Prev
-                a.btn.btn-primary(ng-click='importDomainNext()' ng-disabled='!importDomainNextAvailable()' bs-tooltip='' data-title='{{nextTooltipText()}}' data-placement='bottom') {{importDomain.button}}

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/src/main/js/views/configuration/domains.jade
----------------------------------------------------------------------
diff --git a/modules/web-console/src/main/js/views/configuration/domains.jade b/modules/web-console/src/main/js/views/configuration/domains.jade
deleted file mode 100644
index 7f3253e..0000000
--- a/modules/web-console/src/main/js/views/configuration/domains.jade
+++ /dev/null
@@ -1,66 +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.
-
-include ../../app/helpers/jade/mixins.jade
-
-.docs-header
-    h1 Configure Domain Model And SQL Queries
-.docs-body(ng-controller='domainsController')
-    ignite-information
-        ul: li Import database schemas
-            li Configure indexed types
-    div(ignite-loading='loadingDomainModelsScreen' ignite-loading-text='Loading domain models...' ignite-loading-position='top')
-        div(ng-show='ui.ready')
-            hr
-            .padding-bottom-dflt(ng-show='domains && domains.length > 0')
-                table.links(st-table='displayedRows' st-safe-src='domains')
-                    thead
-                        tr
-                            th
-                                .col-sm-9
-                                    .col-sm-6
-                                        lable.labelHeader.labelFormField {{domainModelTitle()}}
-                                    .col-sm-6
-                                        .pull-right.labelLogin.additional-filter(ng-if='(domains | domainsValidation:false:true).length > 0')
-                                            a.labelFormField(ng-if='ui.showValid' ng-click='toggleValid()' bs-tooltip='' data-title='{{::ui.invalidKeyFieldsTooltip}}') Key fields should be configured: {{(displayedRows | domainsValidation:false:true).length}}&nbsp
-                                            a.labelFormField(ng-if='!ui.showValid' ng-click='toggleValid()') Show all domain models: {{displayedRows.length}}&nbsp
-                                .col-sm-3
-                                    input.form-control.pull-right(type='text' st-search='valueType' placeholder='Filter domain models...')
-                        tbody
-                            tr
-                                td
-                                    .scrollable-y(ng-show='(displayedRows | domainsValidation:ui.showValid:true).length > 0' style='max-height: 200px')
-                                        table
-                                            tbody
-                                                tr(ng-repeat='row in (displayedRows | domainsValidation:ui.showValid:true) track by row._id' ignite-bs-affix-update)
-                                                    td
-                                                        a(ng-class='{active: row._id == selectedItem._id}' ng-click='selectItem(row)') {{$index + 1}}) {{row.valueType}}
-                                    label.placeholder(ng-show='(displayedRows | domainsValidation:ui.showValid:true).length == 0') No domain models found
-            .padding-top-dflt(bs-affix)
-                .panel-tip-container(data-placement='bottom' bs-tooltip='' data-title='Create new domain model')
-                    button.btn.btn-primary(id='new-item' ng-click='createItem()') Add domain model
-                .panel-tip-container(bs-tooltip='' data-title='Import domain models from database' data-placement='bottom')
-                    button.btn.btn-primary(ng-click='showImportDomainModal()') Import from database
-                +save-remove-clone-undo-buttons('domain model')
-                .btn-group.panel-tip-container.pull-right(bs-tooltip='' data-title='Import domain models from demo database' data-placement='bottom')
-                hr
-            .bs-affix-fix
-            div(bs-collapse='' data-allow-multiple='true' ng-model='ui.activePanels')
-                form.form-horizontal(name='ui.inputForm' ng-show='contentVisible()' novalidate)
-                    .panel-group
-                        ignite-configuration-domains-general
-                        ignite-configuration-domains-query
-                        ignite-configuration-domains-store

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/src/main/js/views/configuration/igfs.jade
----------------------------------------------------------------------
diff --git a/modules/web-console/src/main/js/views/configuration/igfs.jade b/modules/web-console/src/main/js/views/configuration/igfs.jade
deleted file mode 100644
index b889a97..0000000
--- a/modules/web-console/src/main/js/views/configuration/igfs.jade
+++ /dev/null
@@ -1,51 +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.
-
-include ../../app/helpers/jade/mixins.jade
-
-.docs-header
-    h1 Configure Ignite In-memory File Systems
-.docs-body(ng-controller='igfsController')
-    ignite-information(data-title='Configure IGFS only if you are going to use In-memory File System')
-        ul
-            li Ignite File System (#[a(href='https://apacheignite-fs.readme.io/docs/in-memory-file-system' target='_blank') IGFS]) is an in-memory file system allowing work with files and directories over existing cache infrastructure
-            li IGFS can either work as purely in-memory file system, or delegate to another file system (e.g. various Hadoop file system implementations) acting as a caching layer (see #[a(href='https://apacheignite-fs.readme.io/docs/secondary-file-system' target='_blank') secondary file system]  for more detail)
-            li In addition IGFS provides API to execute map-reduce tasks over file system data
-    div(ignite-loading='loadingIgfsScreen' ignite-loading-text='Loading IGFS screen...' ignite-loading-position='top')
-        div(ng-show='ui.ready')
-            hr
-            +main-table('IGFS', 'igfss', 'igfsName', 'selectItem(row)', '{{$index + 1}}) {{row.name}}', 'name')
-            .padding-top-dflt(bs-affix)
-                .panel-tip-container(data-placement='bottom' bs-tooltip='' data-title='Create new IGFS')
-                    button.btn.btn-primary(id='new-item' ng-click='createItem()') Add IGFS
-                +save-remove-clone-undo-buttons('IGFS')
-                hr
-            .bs-affix-fix
-            div(bs-collapse='' data-allow-multiple='true' ng-model='ui.activePanels')
-                form.form-horizontal(name='ui.inputForm' ng-show='contentVisible()' novalidate)
-                    .panel-group
-                        ignite-configuration-igfs-general
-
-                        +advanced-options-toggle-default
-
-                        div(ng-show='ui.expanded')
-                            ignite-configuration-igfs-secondary
-                            ignite-configuration-igfs-ipc
-                            ignite-configuration-igfs-fragmentizer
-                            ignite-configuration-igfs-dual
-                            ignite-configuration-igfs-misc
-
-                            +advanced-options-toggle-default

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/src/main/js/views/configuration/sidebar.jade
----------------------------------------------------------------------
diff --git a/modules/web-console/src/main/js/views/configuration/sidebar.jade b/modules/web-console/src/main/js/views/configuration/sidebar.jade
deleted file mode 100644
index bba6b25..0000000
--- a/modules/web-console/src/main/js/views/configuration/sidebar.jade
+++ /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.
-
-.row
-    .col-xs-3.col-sm-3.col-md-2.border-right.section-left.greedy
-        .sidebar-nav(bs-affix)
-            ul.menu(ignite-sidebar)
-                li(ng-repeat='item in sidebar.items')
-                    a(ui-sref-active='active' ui-sref='{{::item.sref}}')
-                        span.fa-stack
-                            i.fa.fa-circle-thin.fa-stack-2x
-                            i.fa.fa-stack-1x {{::$index + 1}}
-                        | {{::item.text}}
-
-    .col-xs-9.col-sm-9.col-md-10.border-left.section-right
-        .docs-content(ui-view='')

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/src/main/js/views/configuration/summary-project-structure.jade
----------------------------------------------------------------------
diff --git a/modules/web-console/src/main/js/views/configuration/summary-project-structure.jade b/modules/web-console/src/main/js/views/configuration/summary-project-structure.jade
deleted file mode 100644
index aa09437..0000000
--- a/modules/web-console/src/main/js/views/configuration/summary-project-structure.jade
+++ /dev/null
@@ -1,27 +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.
-.popover.summary-project-structure
-    h3.popover-title
-        label.labelField Project structure
-        button.close(id='summary-project-structure-close' ng-click='$hide()') &times;
-    .popover-content
-        treecontrol.tree-classic(tree-model='projectStructure' options='projectStructureOptions' expanded-nodes='projectStructureExpanded')
-            span(ng-switch='' on='node.type')
-                span(ng-switch-when='folder')
-                    label {{node.name}}
-                span(ng-switch-when='file')
-                    i.fa.fa-file-text-o
-                    label {{node.name}}


[17/52] ignite git commit: Web Console beta-3.

Posted by ak...@apache.org.
http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/src/main/js/app/modules/states/configuration/caches/store.jade
----------------------------------------------------------------------
diff --git a/modules/web-console/src/main/js/app/modules/states/configuration/caches/store.jade b/modules/web-console/src/main/js/app/modules/states/configuration/caches/store.jade
deleted file mode 100644
index 6361e28..0000000
--- a/modules/web-console/src/main/js/app/modules/states/configuration/caches/store.jade
+++ /dev/null
@@ -1,271 +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.
-
-include ../../../../../app/helpers/jade/mixins.jade
-
--var form = 'store'
--var model = 'backupItem'
-
-//- Mixin for DB dialect.
-mixin dialect(lbl, model, name, required, tipTitle, genericDialectName, placeholder)
-    ignite-form-field
-        ignite-form-field-label
-            | #{lbl}
-        ignite-form-field-tooltip
-            | #{tipTitle}
-            ul: li #{genericDialectName}
-                li Oracle database
-                li IBM DB2
-                li Microsoft SQL Server
-                li MySQL
-                li PostgreSQL
-                li H2 database
-        ignite-form-field-dropdown(
-            data-id=name
-            data-name=name
-            data-options='[\
-                {value: "Generic", label: "#{genericDialectName}"},\
-                {value: "Oracle", label: "Oracle"},\
-                {value: "DB2", label: "IBM DB2"},\
-                {value: "SQLServer", label: "Microsoft SQL Server"},\
-                {value: "MySQL", label: "MySQL"},\
-                {value: "PostgreSQL", label: "PostgreSQL"},\
-                {value: "H2", label: "H2 database"}\
-            ]'
-            data-ng-model=model
-            data-ng-required=required
-            data-placeholder=placeholder
-        )
-
-mixin hibernateField(items, field, valid, save, newItem)
-    -var reset = newItem ? 'group.add = []' : 'field.edit = false'
-
-    -var resetOnEnter = newItem ? '(stopblur = true) && (group.add = [{}])' : '(field.edit = false)'
-    -var onEnter = valid + ' && (' + save + '); ' + valid + ' && ' + resetOnEnter + ';'
-
-    -var resetOnBlur = newItem ? '!stopblur && (group.add = [])' : 'field.edit = false'
-    -var onBlur = valid + ' && ( ' + save + '); ' + resetOnBlur + ';'
-
-    ignite-form-field-input-text(
-        data-name='#{field}{{ $index || "" }}'
-        data-ng-model=field
-        data-ng-required='true'
-        data-placeholder='key=value'
-        data-ignite-property-unique=items
-        data-ignite-property-value-specified
-        data-ignite-form-field-input-autofocus='true'
-        ignite-on-enter=onEnter
-        ignite-on-escape=reset
-        ng-blur=onBlur
-    )
-        block
-
-form.panel.panel-default(name=form novalidate)
-    .panel-heading(bs-collapse-toggle='' ng-click='ui.loadPanel("#{form}")')
-        ignite-form-panel-chevron
-        label Store
-        ignite-form-field-tooltip.tipLabel
-            | Cache store settings
-        ignite-form-revert
-    .panel-collapse(role='tabpanel' bs-collapse-target id=form)
-        .panel-body(ng-if='ui.isPanelLoaded("#{form}")')
-            .col-sm-6
-                .settings-row
-                    -var storeFactory = model + '.cacheStoreFactory';
-                    -var storeFactoryKind = storeFactory + '.kind';
-
-                    +dropdown('Store factory:', storeFactoryKind, 'cacheStoreFactory', 'true', 'Not set',
-                        '[\
-                            {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"}\
-                        ]',
-                        'Factory for persistent storage for cache data'
-                    )
-                    span(ng-show=storeFactoryKind ng-init='__.expanded = true')
-                        a.customize(ng-show='__.expanded' ng-click='__.expanded = false') Hide settings
-                        a.customize(ng-hide='__.expanded' ng-click='__.expanded = true') Show settings
-                        .panel-details(ng-show='__.expanded')
-                            div(ng-show='#{storeFactoryKind} === "CacheJdbcPojoStoreFactory"')
-                                -var pojoStoreFactory = storeFactory + '.CacheJdbcPojoStoreFactory'
-                                -var required = storeFactoryKind + ' === "CacheJdbcPojoStoreFactory"'
-
-                                .details-row
-                                    +text('Data source bean name:', pojoStoreFactory + '.dataSourceBean',
-                                        'pojoDataSourceBean', required, 'Input bean name',
-                                        'Name of the data source bean in Spring context')
-                                .details-row
-                                    +dialect('Dialect:', pojoStoreFactory + '.dialect', 'pojoDialect', required,
-                                        'Dialect of SQL implemented by a particular RDBMS:', 'Generic JDBC dialect',
-                                        'Choose JDBC dialect')
-                            div(ng-show='#{storeFactoryKind} === "CacheJdbcBlobStoreFactory"')
-                                -var blobStoreFactory = storeFactory + '.CacheJdbcBlobStoreFactory'
-                                -var blobStoreFactoryVia = blobStoreFactory + '.connectVia'
-
-                                .details-row
-                                    +dropdown('Connect via:', blobStoreFactoryVia, 'connectVia', 'true', 'Choose connection method',
-                                        '[\
-                                            {value: "URL", label: "URL"},\
-                                            {value: "DataSource", label: "Data source"}\
-                                        ]',
-                                        'You can connect to database via:\
-                                        <ul>\
-                                            <li>JDBC URL, for example: jdbc:h2:mem:myDatabase</li>\
-                                            <li>Configured data source</li>\
-                                        </ul>')
-                                div(ng-show='#{blobStoreFactoryVia} === "URL"')
-                                    -var required = storeFactoryKind + ' === "CacheJdbcBlobStoreFactory" && ' + blobStoreFactoryVia + ' === "URL"'
-
-                                    .details-row
-                                        +text('Connection URL:', blobStoreFactory + '.connectionUrl', 'connectionUrl', required, 'Input URL',
-                                            'URL for database access, for example: jdbc:h2:mem:myDatabase')
-                                    .details-row
-                                        +text('User:', blobStoreFactory + '.user', 'user', required, 'Input user name', 'User name for database access')
-                                    .details-row
-                                        label Note, password will be generated as stub
-                                div(ng-show='#{blobStoreFactoryVia} !== "URL"')
-                                    -var required = storeFactoryKind + ' === "CacheJdbcBlobStoreFactory" && ' + blobStoreFactoryVia + '!== "URL"'
-
-                                    .details-row
-                                        +text('Data source bean name:', blobStoreFactory + '.dataSourceBean', 'blobDataSourceBean', required, 'Input bean name',
-                                            'Name of the data source bean in Spring context')
-                                    .details-row
-                                        +dialect('Database:', blobStoreFactory + '.dialect', 'blobDialect', required, 'Supported databases:', 'Generic database', 'Choose database')
-                                .details-row
-                                    +checkbox('Init schema', blobStoreFactory + '.initSchema', 'initSchema',
-                                        'Flag indicating whether DB schema should be initialized by Ignite (default behaviour) or was explicitly created by user')
-                                .details-row
-                                    +text('Create query:', blobStoreFactory + '.createTableQuery', 'createTableQuery', 'false', 'SQL for table creation',
-                                        'Query for table creation in underlying database<br/>\
-                                        Default value: create table if not exists ENTRIES (key binary primary key, val binary)')
-                                .details-row
-                                    +text('Load query:', blobStoreFactory + '.loadQuery', 'loadQuery', 'false', 'SQL for load entry',
-                                        'Query for entry load from underlying database<br/>\
-                                        Default value: select * from ENTRIES where key=?')
-                                .details-row
-                                    +text('Insert query:', blobStoreFactory + '.insertQuery', 'insertQuery', 'false', 'SQL for insert entry',
-                                        'Query for insert entry into underlying database<br/>\
-                                        Default value: insert into ENTRIES (key, val) values (?, ?)')
-                                .details-row
-                                    +text('Update query:', blobStoreFactory + '.updateQuery', 'updateQuery', 'false', 'SQL for update entry',
-                                        'Query for update entry in underlying database<br/>\
-                                        Default value: update ENTRIES set val=? where key=?')
-                                .details-row
-                                    +text('Delete query:', blobStoreFactory + '.deleteQuery', 'deleteQuery', 'false', 'SQL for delete entry',
-                                        'Query for delete entry from underlying database<br/>\
-                                        Default value: delete from ENTRIES where key=?')
-
-                            div(ng-show='#{storeFactoryKind} === "CacheHibernateBlobStoreFactory"')
-                                -var hibernateStoreFactory = storeFactory + '.CacheHibernateBlobStoreFactory'
-                                -var hibernateProperties = hibernateStoreFactory + '.hibernateProperties'
-
-                                .details-row
-                                    ignite-form-group(ng-model=hibernateProperties ng-form=form)
-                                        ignite-form-field-label
-                                            | Hibernate properties
-                                        ignite-form-group-tooltip
-                                            | List of Hibernate properties#[br]
-                                            | For example: connection.url=jdbc:h2:mem:exampleDb
-                                        ignite-form-group-add(ng-click='group.add = [{}]')
-                                            | Add new Hibernate property
-
-                                        -var tipUnique = 'Property with such key already exists!'
-                                        -var tipPropertySpecified = 'Property should be present in format key=value!'
-
-                                        .group-content(ng-if='#{hibernateProperties}.length')
-                                            -var field = 'edit'
-                                            -var valid = 'form[ngModelName].$valid'
-                                            -var unique = 'form[ngModelName].$error.ignitePropertyUnique'
-                                            -var prop = 'form[ngModelName].$error.ignitePropertyValueSpecified'
-                                            -var save = hibernateProperties + '[$index] = ' + field
-
-                                            ignite-form-field(ng-repeat='model in #{hibernateProperties} track by $index' type='internal' name='Hibernate properties')
-                                                .indexField
-                                                    | {{ $index+1 }})
-                                                +table-remove-button(hibernateProperties, 'Remove Hibernate property')
-
-                                                span(ng-hide='field.edit')
-                                                    a.labelFormField(ng-click='field.edit = true') {{ model }}
-                                                span(ng-if='field.edit' ng-init='#{field} = model')
-                                                    +hibernateField(hibernateProperties, field, valid, save, false)
-                                                        +table-save-button(valid, save, false)
-                                                        +error-feedback(unique, 'ignitePropertyUnique', tipUnique)
-                                                        +error-feedback(prop, 'ignitePropertyValueSpecified', tipPropertySpecified)
-
-                                        .group-content(ng-repeat='field in group.add')
-                                            -var field = 'new'
-                                            -var valid = 'form[ngModelName].$valid'
-                                            -var unique = 'form[ngModelName].$error.ignitePropertyUnique'
-                                            -var prop = 'form[ngModelName].$error.ignitePropertyValueSpecified'
-                                            -var save = hibernateProperties + '.push(' + field + ')'
-
-                                            ignite-form-field(type='internal' name='Hibernate property')
-                                                +hibernateField(hibernateProperties, field, valid, save, true)
-                                                    +table-save-button(valid, save, true)
-                                                    +error-feedback(unique, 'ignitePropertyUnique', tipUnique)
-                                                    +error-feedback(prop, 'ignitePropertyValueSpecified', tipPropertySpecified)
-                                        .group-content-empty(ng-if='!(#{hibernateProperties}.length) && !group.add.length')
-                                            | Not defined
-
-                .settings-row
-                    +checkbox('Keep binary in store', model + '.storeKeepBinary', 'storeKeepBinary',
-                        'Flag indicating that CacheStore implementation is working with binary objects instead of Java objects')
-                .settings-row
-                    +checkbox('Load previous value', model + '.loadPreviousValue', 'loadPreviousValue',
-                        'Flag indicating whether value should be loaded from store if it is not in the cache for following cache operations: \
-                        <ul> \
-                            <li>IgniteCache.putIfAbsent()</li> \
-                            <li>IgniteCache.replace()</li> \
-                            <li>IgniteCache.replace()</li> \
-                            <li>IgniteCache.remove()</li> \
-                            <li>IgniteCache.getAndPut()</li> \
-                            <li>IgniteCache.getAndRemove()</li> \
-                            <li>IgniteCache.getAndReplace()</li> \
-                            <li> IgniteCache.getAndPutIfAbsent()</li>\
-                        </ul>')
-                .settings-row
-                    +checkbox('Read-through', model + '.readThrough', 'readThrough', 'Flag indicating whether read-through caching should be used')
-                .settings-row
-                    +checkbox('Write-through', model + '.writeThrough', 'writeThrough', 'Flag indicating whether write-through caching should be used')
-                .settings-row
-                    ignite-form-group
-                        ignite-form-field-label
-                            | Write behind
-                        ignite-form-group-tooltip
-                            | Cache write behind settings#[br]
-                            | Write-behind is a special mode when updates to cache accumulated and then asynchronously flushed to persistent store as a bulk operation
-                        .group-content
-                            -var enabled = model + '.writeBehindEnabled'
-
-                            .details-row
-                                +checkbox('Enabled', enabled, 'writeBehindEnabled', 'Flag indicating whether Ignite should use write-behind behaviour for the cache store')
-                            .details-row
-                                +number('Batch size:', model + '.writeBehindBatchSize', 'writeBehindBatchSize', enabled, '512', '1',
-                                    'Maximum batch size for write - behind cache store operations<br/>\
-                                     Store operations(get or remove) are combined in a batch of this size to be passed to cache store')
-                            .details-row
-                                +number('Flush size:', model + '.writeBehindFlushSize', 'writeBehindFlushSize', enabled, '10240', '1',
-                                    'Maximum size of the write-behind cache<br/>\
-                                     If cache size exceeds this value, all cached items are flushed to the cache store and write cache is cleared')
-                            .details-row
-                                +number('Flush frequency:', model + '.writeBehindFlushFrequency', 'writeBehindFlushFrequency', enabled, '5000', '1',
-                                    'Frequency with which write-behind cache is flushed to the cache store in milliseconds')
-                            .details-row
-                                +number('Flush threads count:', model + '.writeBehindFlushThreadCount', 'writeBehindFlushThreadCount', enabled, '1', '1',
-                                    'Number of threads that will perform cache flushing')
-            .col-sm-6
-                +preview-xml-java(model, 'cacheStore', 'domains')

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/src/main/js/app/modules/states/configuration/clusters/atomic.directive.js
----------------------------------------------------------------------
diff --git a/modules/web-console/src/main/js/app/modules/states/configuration/clusters/atomic.directive.js b/modules/web-console/src/main/js/app/modules/states/configuration/clusters/atomic.directive.js
deleted file mode 100644
index 64b80a0..0000000
--- a/modules/web-console/src/main/js/app/modules/states/configuration/clusters/atomic.directive.js
+++ /dev/null
@@ -1,27 +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 templateUrl from './atomic.jade';
-
-export default ['igniteConfigurationClustersAtomic', [() => {
-    return {
-        scope: true,
-        restrict: 'E',
-        templateUrl,
-        replace: true
-    };
-}]];

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/src/main/js/app/modules/states/configuration/clusters/atomic.jade
----------------------------------------------------------------------
diff --git a/modules/web-console/src/main/js/app/modules/states/configuration/clusters/atomic.jade b/modules/web-console/src/main/js/app/modules/states/configuration/clusters/atomic.jade
deleted file mode 100644
index 3927b72..0000000
--- a/modules/web-console/src/main/js/app/modules/states/configuration/clusters/atomic.jade
+++ /dev/null
@@ -1,53 +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.
-
-include ../../../../../app/helpers/jade/mixins.jade
-
--var form = 'atomics'
--var model = 'backupItem.atomicConfiguration'
-
-form.panel.panel-default(name=form novalidate)
-    .panel-heading(bs-collapse-toggle='' ng-click='ui.loadPanel("#{form}")')
-        ignite-form-panel-chevron
-        label Atomic configuration
-        ignite-form-field-tooltip.tipLabel
-            | Configuration for atomic data structures#[br]
-            | Atomics are distributed across the cluster, essentially enabling performing atomic operations (such as increment-and-get or compare-and-set) with the same globally-visible value
-        ignite-form-revert 
-    .panel-collapse(role='tabpanel' bs-collapse-target='' id=form)
-        .panel-body(ng-if='ui.isPanelLoaded("#{form}")')
-            .col-sm-6
-                .settings-row
-                    +dropdown('Cache mode:', model + '.cacheMode', 'cacheMode', 'true', 'PARTITIONED',
-                        '[\
-                            {value: "LOCAL", label: "LOCAL"},\
-                            {value: "REPLICATED", label: "REPLICATED"},\
-                            {value: "PARTITIONED", label: "PARTITIONED"}\
-                        ]',
-                        'Cache modes:\
-                        <ul>\
-                            <li>Partitioned - in this mode the overall key set will be divided into partitions and all partitions will be split equally between participating nodes</li>\
-                            <li>Replicated - in this mode all the keys are distributed to all participating nodes</li>\
-                            <li>Local - in this mode caches residing on different grid nodes will not know about each other</li>\
-                        </ul>')
-                .settings-row
-                    +number('Sequence reserve:', model + '.atomicSequenceReserveSize', 'atomicSequenceReserveSize', 'true', '1000', '0',
-                        'Default number of sequence values reserved for IgniteAtomicSequence instances<br/>\
-                        After a certain number has been reserved, consequent increments of sequence will happen locally, without communication with other nodes, until the next reservation has to be made')
-                .settings-row(ng-if='!(#{model}.cacheMode && #{model}.cacheMode != "PARTITIONED")')
-                    +number('Backups:', model + '.backups', 'backups', 'true', '0', '0', 'Number of backup nodes')
-            .col-sm-6
-                +preview-xml-java(model, 'clusterAtomics')

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/src/main/js/app/modules/states/configuration/clusters/attributes.directive.js
----------------------------------------------------------------------
diff --git a/modules/web-console/src/main/js/app/modules/states/configuration/clusters/attributes.directive.js b/modules/web-console/src/main/js/app/modules/states/configuration/clusters/attributes.directive.js
deleted file mode 100644
index f5f431c..0000000
--- a/modules/web-console/src/main/js/app/modules/states/configuration/clusters/attributes.directive.js
+++ /dev/null
@@ -1,27 +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 templateUrl from './attributes.jade';
-
-export default ['igniteConfigurationUserAttributes', [() => {
-    return {
-        scope: true,
-        restrict: 'E',
-        templateUrl,
-        replace: true
-    };
-}]];

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/src/main/js/app/modules/states/configuration/clusters/attributes.jade
----------------------------------------------------------------------
diff --git a/modules/web-console/src/main/js/app/modules/states/configuration/clusters/attributes.jade b/modules/web-console/src/main/js/app/modules/states/configuration/clusters/attributes.jade
deleted file mode 100644
index e6ffd50..0000000
--- a/modules/web-console/src/main/js/app/modules/states/configuration/clusters/attributes.jade
+++ /dev/null
@@ -1,58 +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.
-
-include ../../../../../app/helpers/jade/mixins.jade
-
--var form = 'attributes'
--var model = 'backupItem'
--var types = model + '.typeConfigurations'
--var userAttributes = model + '.attributes'
-
-form.panel.panel-default(name=form novalidate)
-    .panel-heading(bs-collapse-toggle ng-click='ui.loadPanel("#{form}")')
-        ignite-form-panel-chevron
-        label User attributes
-        ignite-form-field-tooltip.tipLabel
-            | Configuration for Ignite user attributes
-        ignite-form-revert
-    .panel-collapse(role='tabpanel' bs-collapse-target id=form)
-        .panel-body(ng-if='ui.isPanelLoaded("#{form}")')
-            .col-sm-6
-                .settings-row
-                    ignite-form-group(ng-model='#{userAttributes}' ng-form='#{form}')
-                        ignite-form-field-label
-                            | User attributes
-                        ignite-form-group-tooltip
-                            | User-defined attributes to add to node
-                        ignite-form-group-add(ng-click='tableNewItem(attributesTbl)')
-                            | Add user attribute
-                        .group-content-empty(ng-if='!((#{userAttributes} && #{userAttributes}.length > 0) || tableNewItemActive(attributesTbl))')
-                            | Not defined
-                        .group-content(ng-show='(#{userAttributes} && #{userAttributes}.length > 0) || tableNewItemActive(attributesTbl)')
-                            table.links-edit(id='attributes' st-table=userAttributes)
-                                tbody
-                                    tr(ng-repeat='item in #{userAttributes}')
-                                        td.col-sm-12(ng-show='!tableEditing(attributesTbl, $index)')
-                                            a.labelFormField(ng-click='tableStartEdit(backupItem, attributesTbl, $index)') {{item.name}} = {{item.value}}
-                                            +btn-remove('tableRemove(backupItem, attributesTbl, $index)', '"Remove attribute"')
-                                        td.col-sm-12(ng-show='tableEditing(attributesTbl, $index)')
-                                            +table-pair-edit('attributesTbl', 'cur', 'Attribute name', 'Attribute value', false, false, '{{::attributesTbl.focusId + $index}}', '$index', '=')
-                                tfoot(ng-show='tableNewItemActive(attributesTbl)')
-                                    tr
-                                        td.col-sm-12
-                                            +table-pair-edit('attributesTbl', 'new', 'Attribute name', 'Attribute value', false, false, '{{::attributesTbl.focusId + $index}}', '-1', '=')
-            .col-sm-6
-                +preview-xml-java(model, 'clusterUserAttributes')

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/src/main/js/app/modules/states/configuration/clusters/binary.directive.js
----------------------------------------------------------------------
diff --git a/modules/web-console/src/main/js/app/modules/states/configuration/clusters/binary.directive.js b/modules/web-console/src/main/js/app/modules/states/configuration/clusters/binary.directive.js
deleted file mode 100644
index 7d701bc..0000000
--- a/modules/web-console/src/main/js/app/modules/states/configuration/clusters/binary.directive.js
+++ /dev/null
@@ -1,27 +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 templateUrl from './binary.jade';
-
-export default ['igniteConfigurationClustersBinary', [() => {
-    return {
-        scope: true,
-        restrict: 'E',
-        templateUrl,
-        replace: true
-    };
-}]];

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/src/main/js/app/modules/states/configuration/clusters/binary.jade
----------------------------------------------------------------------
diff --git a/modules/web-console/src/main/js/app/modules/states/configuration/clusters/binary.jade b/modules/web-console/src/main/js/app/modules/states/configuration/clusters/binary.jade
deleted file mode 100644
index 77caa36..0000000
--- a/modules/web-console/src/main/js/app/modules/states/configuration/clusters/binary.jade
+++ /dev/null
@@ -1,100 +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.
-
-include ../../../../../app/helpers/jade/mixins.jade
-
--var form = 'binary'
--var model = 'backupItem.binaryConfiguration'
--var types = model + '.typeConfigurations'
-
-//- Mixin for java name field with enabled condition.
-mixin binary-types-java-class(lbl, model, name, enabled, required, remove, autofocus, tip)
-    -var errLbl = lbl.substring(0, lbl.length - 1)
-
-    ignite-form-field
-        ignite-form-field-label
-            | #{lbl}
-        ignite-form-field-tooltip
-            | !{tip}
-        if (remove)
-            +table-remove-button(types, 'Remove type configuration')
-        ignite-form-field-input-text(
-            data-id='{{#{name}}}'
-            data-name='{{#{name}}}'
-            data-ng-model=model
-            data-ng-disabled='!(#{enabled})'
-            data-ng-required=required
-            data-placeholder='Enter fully qualified class name'
-
-            data-ignite-form-field-input-autofocus=autofocus
-
-            data-java-identifier='true'
-            data-java-package-specified='true'
-            data-java-keywords='true'
-            data-java-built-in-class='true'
-        )
-            +error-feedback('form[ngModelName].$error.javaBuiltInClass', 'javaBuiltInClass', lbl + ' should not be the Java built-in class!', '{{' + name + '}}')
-            +error-feedback('form[ngModelName].$error.javaKeywords', 'javaKeywords', lbl + ' could not contains reserved Java keyword!', '{{' + name + '}}')
-            +error-feedback('form[ngModelName].$error.javaPackageSpecified', 'javaPackageSpecified', lbl + ' does not have package specified!', '{{' + name + '}}')
-            +error-feedback('form[ngModelName].$error.javaIdentifier', 'javaIdentifier', lbl + ' is invalid Java identifier!', '{{' + name + '}}')
-
-form.panel.panel-default(name=form novalidate)
-    .panel-heading(bs-collapse-toggle ng-click='ui.loadPanel("#{form}")')
-        ignite-form-panel-chevron
-        label Binary configuration
-        ignite-form-field-tooltip.tipLabel
-            | Configuration for Ignite Binary Objects
-        ignite-form-revert
-    .panel-collapse(role='tabpanel' bs-collapse-target id=form)
-        .panel-body(ng-if='ui.isPanelLoaded("#{form}")')
-            .col-sm-6
-                .settings-row
-                    +java-class('ID mapper:', model + '.idMapper', 'idMapper', 'true', 'false',
-                        'Maps given from BinaryNameMapper type and filed name to ID that will be used by Ignite in internals<br/>\
-                        Ignite never writes full strings for field or type names. Instead, for performance reasons, Ignite writes integer hash codes for type/class and field names. It has been tested that hash code conflicts for the type/class names or the field names within the same type are virtually non - existent and, to gain performance, it is safe to work with hash codes. For the cases when hash codes for different types or fields actually do collide <b>BinaryIdMapper</b> allows to override the automatically generated hash code IDs for the type and field names')
-                .settings-row
-                    +java-class('Name mapper:', model + '.nameMapper', 'nameMapper', 'true', 'false', 'Maps type/class and field names to different names')
-                .settings-row
-                    +java-class('Serializer:', model + '.serializer', 'serializer', 'true', 'false', 'Class with custom serialization logic for binary objects')
-                .settings-row
-                    ignite-form-group(ng-form='#{form}TypeConfigurations' ng-model='#{types}')
-                        ignite-form-field-label
-                            | Type configurations
-                        ignite-form-group-tooltip
-                            | Configuration properties for binary types
-                        ignite-form-group-add(ng-click='#{types}.push({})')
-                            | Add new type configuration.
-                        .group-content-empty(ng-if='!#{types}.length')
-                            | Not defined
-                        .group-content(ng-repeat='model in #{types} track by $index')
-                            hr(ng-if='$index !== 0')
-                            .settings-row
-                                +binary-types-java-class('Type name:', 'model.typeName', '"typeName" + $index', 'true', 'true', true, 'true', 'Type name')
-                            .settings-row
-                                +binary-types-java-class('ID mapper:', 'model.idMapper', '"idMapper" + $index', 'true', 'false', false, 'false',
-                                    'Maps given from BinaryNameMapper type and filed name to ID that will be used by Ignite in internals<br/>\
-                                    Ignite never writes full strings for field or type/class names. Instead, for performance reasons, Ignite writes integer hash codes for type/class and field names. It has been tested that hash code conflicts for the type/class names or the field names within the same type are virtually non - existent and, to gain performance, it is safe to work with hash codes. For the cases when hash codes for different types or fields actually do collide #[b BinaryIdMapper] allows to override the automatically generated hash code IDs for the type and field names')
-                            .settings-row
-                                +binary-types-java-class('Name mapper:', 'model.nameMapper', '"nameMapper" + $index', 'true', 'false', false, 'false', 'Maps type/class and field names to different names')
-                            .settings-row
-                                +binary-types-java-class('Serializer:', 'model.serializer', '"serializer" + $index', 'true', 'false', false, 'false', 'Class with custom serialization logic for binary object')
-                            .settings-row
-                                +checkbox('Enum', 'model.enum', 'enum', 'Flag indicating that this type is the enum')
-
-                .settings-row
-                    +checkbox('Compact footer', model + '.compactFooter', 'compactFooter', 'When enabled, Ignite will not write fields metadata when serializing objects(this will increase serialization performance), because internally #[b BinaryMarshaller] already distribute metadata inside cluster')
-            .col-sm-6
-                +preview-xml-java(model, 'clusterBinary')

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/src/main/js/app/modules/states/configuration/clusters/collision.directive.js
----------------------------------------------------------------------
diff --git a/modules/web-console/src/main/js/app/modules/states/configuration/clusters/collision.directive.js b/modules/web-console/src/main/js/app/modules/states/configuration/clusters/collision.directive.js
deleted file mode 100644
index b8e0b43..0000000
--- a/modules/web-console/src/main/js/app/modules/states/configuration/clusters/collision.directive.js
+++ /dev/null
@@ -1,27 +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 templateUrl from './collision.jade';
-
-export default ['igniteConfigurationClustersCollision', [() => {
-    return {
-        scope: true,
-        restrict: 'E',
-        templateUrl,
-        replace: true
-    };
-}]];

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/src/main/js/app/modules/states/configuration/clusters/collision.jade
----------------------------------------------------------------------
diff --git a/modules/web-console/src/main/js/app/modules/states/configuration/clusters/collision.jade b/modules/web-console/src/main/js/app/modules/states/configuration/clusters/collision.jade
deleted file mode 100644
index 10e51f0..0000000
--- a/modules/web-console/src/main/js/app/modules/states/configuration/clusters/collision.jade
+++ /dev/null
@@ -1,60 +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.
-
-include ../../../../../app/helpers/jade/mixins.jade
-
--var form = 'collision'
--var model = 'backupItem.collision'
-
-form.panel.panel-default(name=form novalidate)
-    .panel-heading(bs-collapse-toggle ng-click='ui.loadPanel("#{form}")')
-        ignite-form-panel-chevron
-        label Collision configuration
-        ignite-form-field-tooltip.tipLabel
-            | Configuration Collision SPI allows to regulate how grid jobs get executed when they arrive on a destination node for execution
-        ignite-form-revert
-    .panel-collapse(role='tabpanel' bs-collapse-target id=form)
-        .panel-body(ng-if='ui.isPanelLoaded("#{form}")')
-            .col-sm-6
-                .settings-row
-                    +dropdown('CollisionSpi:', model + '.kind', 'collision', 'true', '',
-                        '[\
-                            {value: "JobStealing", label: "Job stealing"},\
-                            {value: "FifoQueue", label: "FIFO queue"},\
-                            {value: "PriorityQueue", label: "Priority queue"},\
-                            {value: "Custom", label: "Custom"},\
-                            {value: "Noop", label: "Default"}\
-                        ]',
-                        'Regulate how grid jobs get executed when they arrive on a destination node for execution\
-                        <ul>\
-                            <li>Job stealing - supports job stealing from over-utilized nodes to under-utilized nodes</li>\
-                            <li>FIFO queue - jobs are ordered as they arrived</li>\
-                            <li>Priority queue - jobs are first ordered by their priority</li>\
-                            <li>Custom - custom CollisionSpi implementation</li>\
-                            <li>Default - jobs are activated immediately on arrival to mapped node</li>\
-                        </ul>')
-                .settings-row(ng-show='#{model}.kind !== "Noop"')
-                    .panel-details
-                        ignite-configuration-clusters-collision-job-stealing(
-                            ng-show='#{model}.kind === "JobStealing"')
-                        ignite-configuration-clusters-collision-fifo-queue(
-                            ng-show='#{model}.kind === "FifoQueue"')
-                        ignite-configuration-clusters-collision-priority-queue(
-                            ng-show='#{model}.kind === "PriorityQueue"')
-                        ignite-configuration-clusters-collision-custom(
-                            ng-show='#{model}.kind === "Custom"')
-            .col-sm-6
-                +preview-xml-java(model, 'clusterCollision')

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/src/main/js/app/modules/states/configuration/clusters/collision/custom.directive.js
----------------------------------------------------------------------
diff --git a/modules/web-console/src/main/js/app/modules/states/configuration/clusters/collision/custom.directive.js b/modules/web-console/src/main/js/app/modules/states/configuration/clusters/collision/custom.directive.js
deleted file mode 100644
index 2299133..0000000
--- a/modules/web-console/src/main/js/app/modules/states/configuration/clusters/collision/custom.directive.js
+++ /dev/null
@@ -1,27 +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 templateUrl from './custom.jade';
-
-export default ['igniteConfigurationClustersCollisionCustom', [() => {
-    return {
-        scope: true,
-        restrict: 'E',
-        templateUrl,
-        replace: true
-    };
-}]];

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/src/main/js/app/modules/states/configuration/clusters/collision/custom.jade
----------------------------------------------------------------------
diff --git a/modules/web-console/src/main/js/app/modules/states/configuration/clusters/collision/custom.jade b/modules/web-console/src/main/js/app/modules/states/configuration/clusters/collision/custom.jade
deleted file mode 100644
index b666f54..0000000
--- a/modules/web-console/src/main/js/app/modules/states/configuration/clusters/collision/custom.jade
+++ /dev/null
@@ -1,24 +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.
-
-include ../../../../../../app/helpers/jade/mixins.jade
-
--var model = 'backupItem.collision.Custom'
--var required = 'backupItem.collision.kind === "Custom"'
-
-div
-    .details-row
-        +java-class('Class:', model + '.class', 'collisionCustom', 'true', required, 'CollisionSpi implementation class')

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/src/main/js/app/modules/states/configuration/clusters/collision/fifo-queue.directive.js
----------------------------------------------------------------------
diff --git a/modules/web-console/src/main/js/app/modules/states/configuration/clusters/collision/fifo-queue.directive.js b/modules/web-console/src/main/js/app/modules/states/configuration/clusters/collision/fifo-queue.directive.js
deleted file mode 100644
index f14c1bb..0000000
--- a/modules/web-console/src/main/js/app/modules/states/configuration/clusters/collision/fifo-queue.directive.js
+++ /dev/null
@@ -1,27 +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 templateUrl from './fifo-queue.jade';
-
-export default ['igniteConfigurationClustersCollisionFifoQueue', [() => {
-    return {
-        scope: true,
-        restrict: 'E',
-        templateUrl,
-        replace: true
-    };
-}]];

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/src/main/js/app/modules/states/configuration/clusters/collision/fifo-queue.jade
----------------------------------------------------------------------
diff --git a/modules/web-console/src/main/js/app/modules/states/configuration/clusters/collision/fifo-queue.jade b/modules/web-console/src/main/js/app/modules/states/configuration/clusters/collision/fifo-queue.jade
deleted file mode 100644
index 9c9d315..0000000
--- a/modules/web-console/src/main/js/app/modules/states/configuration/clusters/collision/fifo-queue.jade
+++ /dev/null
@@ -1,28 +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.
-
-include ../../../../../../app/helpers/jade/mixins.jade
-
--var model = 'backupItem.collision.FifoQueue'
--var form = 'collisionFifoQueue'
-
-div
-    .details-row
-        +number('Parallel jobs number:', model + '.parallelJobsNumber', 'fifoParallelJobsNumber', 'true', 'availableProcessors * 2', '1',
-            'Number of jobs that can be executed in parallel')
-    .details-row
-        +number('Wait jobs number:', model + '.waitingJobsNumber', 'fifoWaitingJobsNumber', 'true', 'Integer.MAX_VALUE', '0',
-            'Maximum number of jobs that are allowed to wait in waiting queue')

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/src/main/js/app/modules/states/configuration/clusters/collision/job-stealing.directive.js
----------------------------------------------------------------------
diff --git a/modules/web-console/src/main/js/app/modules/states/configuration/clusters/collision/job-stealing.directive.js b/modules/web-console/src/main/js/app/modules/states/configuration/clusters/collision/job-stealing.directive.js
deleted file mode 100644
index 0cc9cfa..0000000
--- a/modules/web-console/src/main/js/app/modules/states/configuration/clusters/collision/job-stealing.directive.js
+++ /dev/null
@@ -1,27 +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 templateUrl from './job-stealing.jade';
-
-export default ['igniteConfigurationClustersCollisionJobStealing', [() => {
-    return {
-        scope: true,
-        restrict: 'E',
-        templateUrl,
-        replace: true
-    };
-}]];

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/src/main/js/app/modules/states/configuration/clusters/collision/job-stealing.jade
----------------------------------------------------------------------
diff --git a/modules/web-console/src/main/js/app/modules/states/configuration/clusters/collision/job-stealing.jade b/modules/web-console/src/main/js/app/modules/states/configuration/clusters/collision/job-stealing.jade
deleted file mode 100644
index 17392c0..0000000
--- a/modules/web-console/src/main/js/app/modules/states/configuration/clusters/collision/job-stealing.jade
+++ /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.
-
-include ../../../../../../app/helpers/jade/mixins.jade
-
--var model = 'backupItem.collision.JobStealing'
--var form = 'collisionJobStealing'
--var stealingAttributes = model + '.stealingAttributes'
-
-div
-    .details-row
-        +number('Active jobs threshold:', model + '.activeJobsThreshold', 'jsActiveJobsThreshold', 'true', '95', '0',
-            'Number of jobs that can be executed in parallel')
-    .details-row
-        +number('Wait jobs threshold:', model + '.waitJobsThreshold', 'jsWaitJobsThreshold', 'true', '0', '0',
-            'Job count threshold at which this node will start stealing jobs from other nodes')
-    .details-row
-        +number('Message expire time:', model + '.messageExpireTime', 'jsMessageExpireTime', 'true', '1000', '1',
-            'Message expire time in ms')
-    .details-row
-        +number('Maximum stealing attempts:', model + '.maximumStealingAttempts', 'jsMaximumStealingAttempts', 'true', '5', '1',
-            'Maximum number of attempts to steal job by another node')
-    .details-row
-        +checkbox('Stealing enabled', model + '.stealingEnabled', 'jsStealingEnabled',
-            'Node should attempt to steal jobs from other nodes')
-    .details-row
-        +java-class('External listener:', model + '.externalCollisionListener', 'jsExternalCollisionListener', 'true', 'false',
-            'Listener to be set for notification of external collision events')
-    .details-row
-        ignite-form-group(ng-model='#{stealingAttributes}' ng-form='#{form}')
-            ignite-form-field-label
-                | Stealing attributes
-            ignite-form-group-tooltip
-                | Configuration parameter to enable stealing to/from only nodes that have these attributes set
-            ignite-form-group-add(ng-click='tableNewItem(stealingAttributesTbl)')
-                | Add stealing attribute
-            .group-content-empty(ng-if='!((#{stealingAttributes} && #{stealingAttributes}.length > 0) || tableNewItemActive(stealingAttributesTbl))')
-                | Not defined
-            .group-content(ng-show='(#{stealingAttributes} && #{stealingAttributes}.length > 0) || tableNewItemActive(stealingAttributesTbl)')
-                table.links-edit(id='attributes' st-table=stealingAttributes)
-                    tbody
-                        tr(ng-repeat='item in #{stealingAttributes}')
-                            td.col-sm-12(ng-show='!tableEditing(stealingAttributesTbl, $index)')
-                                a.labelFormField(ng-click='tableStartEdit(backupItem, stealingAttributesTbl, $index)') {{item.name}} = {{item.value}}
-                                +btn-remove('tableRemove(backupItem, stealingAttributesTbl, $index)', '"Remove attribute"')
-                            td.col-sm-12(ng-show='tableEditing(stealingAttributesTbl, $index)')
-                                +table-pair-edit('stealingAttributesTbl', 'cur', 'Attribute name', 'Attribute value', false, false, '{{::stealingAttributesTbl.focusId + $index}}', '$index', '=')
-                    tfoot(ng-show='tableNewItemActive(stealingAttributesTbl)')
-                        tr
-                            td.col-sm-12
-                                +table-pair-edit('stealingAttributesTbl', 'new', 'Attribute name', 'Attribute value', false, false, '{{::stealingAttributesTbl.focusId + $index}}', '-1', '=')

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/src/main/js/app/modules/states/configuration/clusters/collision/priority-queue.directive.js
----------------------------------------------------------------------
diff --git a/modules/web-console/src/main/js/app/modules/states/configuration/clusters/collision/priority-queue.directive.js b/modules/web-console/src/main/js/app/modules/states/configuration/clusters/collision/priority-queue.directive.js
deleted file mode 100644
index 95ebd5e..0000000
--- a/modules/web-console/src/main/js/app/modules/states/configuration/clusters/collision/priority-queue.directive.js
+++ /dev/null
@@ -1,27 +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 templateUrl from './priority-queue.jade';
-
-export default ['igniteConfigurationClustersCollisionPriorityQueue', [() => {
-    return {
-        scope: true,
-        restrict: 'E',
-        templateUrl,
-        replace: true
-    };
-}]];

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/src/main/js/app/modules/states/configuration/clusters/collision/priority-queue.jade
----------------------------------------------------------------------
diff --git a/modules/web-console/src/main/js/app/modules/states/configuration/clusters/collision/priority-queue.jade b/modules/web-console/src/main/js/app/modules/states/configuration/clusters/collision/priority-queue.jade
deleted file mode 100644
index 208c12b..0000000
--- a/modules/web-console/src/main/js/app/modules/states/configuration/clusters/collision/priority-queue.jade
+++ /dev/null
@@ -1,43 +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.
-
-include ../../../../../../app/helpers/jade/mixins.jade
-
--var model = 'backupItem.collision.PriorityQueue'
--var form = 'collisionPriorityQueue'
-
-div
-    .details-row
-        +number('Parallel jobs number:', model + '.parallelJobsNumber', 'priorityParallelJobsNumber', 'true', 'availableProcessors * 2', '1',
-            'Number of jobs that can be executed in parallel')
-    .details-row
-        +number('Waiting jobs number:', model + '.waitingJobsNumber', 'priorityWaitingJobsNumber', 'true', 'Integer.MAX_VALUE', '0',
-            'Maximum number of jobs that are allowed to wait in waiting queue')
-    .details-row
-        +text('Priority attribute key:', model + '.priorityAttributeKey', 'priorityPriorityAttributeKey', 'false', 'grid.task.priority',
-            'Task priority attribute key')
-    .details-row
-        +text('Job priority attribute key:', model + '.jobPriorityAttributeKey', 'priorityJobPriorityAttributeKey', 'false', 'grid.job.priority',
-            'Job priority attribute key')
-    .details-row
-        +number('Default priority:', model + '.defaultPriority', 'priorityDefaultPriority', 'true', '0', '0',
-            'Default priority to use if a job does not have priority attribute set')
-    .details-row
-        +number('Starvation increment:', model + '.starvationIncrement', 'priorityStarvationIncrement', 'true', '1', '0',
-            'Value to increment job priority by every time a lower priority job gets behind a higher priority job')
-    .details-row
-        +checkbox('Starvation prevention enabled', model + '.starvationPreventionEnabled', 'priorityStarvationPreventionEnabled',
-            'Job starvation prevention is enabled')

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/src/main/js/app/modules/states/configuration/clusters/communication.directive.js
----------------------------------------------------------------------
diff --git a/modules/web-console/src/main/js/app/modules/states/configuration/clusters/communication.directive.js b/modules/web-console/src/main/js/app/modules/states/configuration/clusters/communication.directive.js
deleted file mode 100644
index e578dc6..0000000
--- a/modules/web-console/src/main/js/app/modules/states/configuration/clusters/communication.directive.js
+++ /dev/null
@@ -1,27 +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 templateUrl from './communication.jade';
-
-export default ['igniteConfigurationClustersCommunication', [() => {
-    return {
-        scope: true,
-        restrict: 'E',
-        templateUrl,
-        replace: true
-    };
-}]];

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/src/main/js/app/modules/states/configuration/clusters/communication.jade
----------------------------------------------------------------------
diff --git a/modules/web-console/src/main/js/app/modules/states/configuration/clusters/communication.jade b/modules/web-console/src/main/js/app/modules/states/configuration/clusters/communication.jade
deleted file mode 100644
index 7073f27..0000000
--- a/modules/web-console/src/main/js/app/modules/states/configuration/clusters/communication.jade
+++ /dev/null
@@ -1,96 +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.
-
-include ../../../../../app/helpers/jade/mixins.jade
-
--var form = 'communication'
--var model = 'backupItem'
--var communication = model + '.communication'
-
-form.panel.panel-default(name=form novalidate)
-    .panel-heading(bs-collapse-toggle ng-click='ui.loadPanel("#{form}")')
-        ignite-form-panel-chevron
-        label Communication
-        ignite-form-field-tooltip.tipLabel
-            | Cluster communication network properties
-        ignite-form-revert
-    .panel-collapse(role='tabpanel' bs-collapse-target id=form)
-        .panel-body(ng-if='ui.isPanelLoaded("#{form}")')
-            .col-sm-6
-                .settings-row
-                    +number('Timeout:', model + '.networkTimeout', 'commNetworkTimeout', 'true', '5000', '1', 'Maximum timeout in milliseconds for network requests')
-                .settings-row
-                    +number('Send retry delay:', model + '.networkSendRetryDelay', 'networkSendRetryDelay', 'true', '1000', '1', 'Interval in milliseconds between message send retries')
-                .settings-row
-                    +number('Send retry count:', model + '.networkSendRetryCount', 'networkSendRetryCount', 'true', '3', '1', 'Message send retries count')
-                .settings-row
-                    +number('Discovery startup delay:', model + '.discoveryStartupDelay', 'discoveryStartupDelay', 'true', '60000', '1', 'This value is used to expire messages from waiting list whenever node discovery discrepancies happen')
-                .settings-row
-                    +java-class('Communication listener:', communication + '.listener', 'comListener', 'true', 'false', 'Communication listener')
-                .settings-row
-                    +text-ip-address('Local IP address:', communication + '.localAddress', 'comLocalAddress', 'true', '0.0.0.0', 'Local host address for socket binding')
-                .settings-row
-                    +number-min-max('Local port:', communication + '.localPort', 'comLocalPort', 'true', '47100', '1024', '65535', 'Local port for socket binding')
-                .settings-row
-                    +number('Local port range:', communication + '.localPortRange', 'comLocalPortRange', 'true', '100', '1', 'Local port range for local host ports')
-                .settings-row
-                    +number-min-max('Shared memory port:', communication + '.sharedMemoryPort', 'sharedMemoryPort', 'true', '48100', '-1', '65535',
-                        'Local port to accept shared memory connections<br/>\
-                        If set to #[b -1] shared memory communication will be disabled')
-                .settings-row
-                    +number('Idle connection timeout:', communication + '.idleConnectionTimeout', 'idleConnectionTimeout', 'true', '30000', '1',
-                        'Maximum idle connection timeout upon which a connection to client will be closed')
-                .settings-row
-                    +number('Connect timeout:', communication + '.connectTimeout', 'connectTimeout', 'true', '5000', '0', 'Connect timeout used when establishing connection with remote nodes')
-                .settings-row
-                    +number('Maximum connect timeout:', communication + '.maxConnectTimeout', 'maxConnectTimeout', 'true', '600000', '0', 'Maximum connect timeout')
-                .settings-row
-                    +number('Reconnect count:', communication + '.reconnectCount', 'comReconnectCount', 'true', '10', '1',
-                        'Maximum number of reconnect attempts used when establishing connection with remote nodes')
-                .settings-row
-                    +number('Socket send buffer:', communication + '.socketSendBuffer', 'socketSendBuffer', 'true', '32768', '0', 'Send buffer size for sockets created or accepted by this SPI')
-                .settings-row
-                    +number('Socket receive buffer:', communication + '.socketReceiveBuffer', 'socketReceiveBuffer', 'true', '32768', '0', 'Receive buffer size for sockets created or accepted by this SPI')
-                .settings-row
-                    +number('Slow client queue limit:', communication + '.slowClientQueueLimit', 'slowClientQueueLimit', 'true', '0', '0', 'Slow client queue limit')
-                .settings-row
-                    +number('Ack send threshold:', communication + '.ackSendThreshold', 'ackSendThreshold', 'true', '16', '1', 'Number of received messages per connection to node after which acknowledgment message is sent')
-                .settings-row
-                    +number('Message queue limit:', communication + '.messageQueueLimit', 'messageQueueLimit', 'true', '1024', '0', 'Message queue limit for incoming and outgoing messages')
-                .settings-row
-                    +number('Unacknowledged messages:', communication + '.unacknowledgedMessagesBufferSize', 'unacknowledgedMessagesBufferSize', 'true', '0', '0',
-                        'Maximum number of stored unacknowledged messages per connection to node<br/>\
-                        If specified non zero value it should be\
-                        <ul>\
-                            <li>At least ack send threshold * 5</li>\
-                            <li>At least message queue limit * 5</li>\
-                        </ul>')
-                .settings-row
-                    +number('Socket write timeout:', communication + '.socketWriteTimeout', 'socketWriteTimeout', 'true', '2000', '0', 'Socket write timeout')
-                .settings-row
-                    +number('Selectors count:', communication + '.selectorsCount', 'selectorsCount', 'true', 'min(4, availableProcessors)', '1', 'Count of selectors te be used in TCP server')
-                .settings-row
-                    +java-class('Address resolver:', communication + '.addressResolver', 'comAddressResolver', 'true', 'false', 'Address resolver')
-                .settings-row
-                    +checkbox('Direct buffer', communication + '.directBuffer', 'directBuffer',
-                    'If value is true, then SPI will use ByteBuffer.allocateDirect(int) call<br/>\
-                    Otherwise, SPI will use ByteBuffer.allocate(int) call.')
-                .settings-row
-                    +checkbox('Direct send buffer', communication + '.directSendBuffer', 'directSendBuffer', 'Flag defining whether direct send buffer should be used')
-                .settings-row
-                    +checkbox('TCP_NODELAY option', communication + '.tcpNoDelay', 'tcpNoDelay', 'Value for TCP_NODELAY socket option')
-            .col-sm-6
-                +preview-xml-java(model, 'clusterCommunication')

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/src/main/js/app/modules/states/configuration/clusters/connector.directive.js
----------------------------------------------------------------------
diff --git a/modules/web-console/src/main/js/app/modules/states/configuration/clusters/connector.directive.js b/modules/web-console/src/main/js/app/modules/states/configuration/clusters/connector.directive.js
deleted file mode 100644
index ea0b04d..0000000
--- a/modules/web-console/src/main/js/app/modules/states/configuration/clusters/connector.directive.js
+++ /dev/null
@@ -1,27 +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 templateUrl from './connector.jade';
-
-export default ['igniteConfigurationClustersConnector', [() => {
-    return {
-        scope: true,
-        restrict: 'E',
-        templateUrl,
-        replace: true
-    };
-}]];

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/src/main/js/app/modules/states/configuration/clusters/connector.jade
----------------------------------------------------------------------
diff --git a/modules/web-console/src/main/js/app/modules/states/configuration/clusters/connector.jade b/modules/web-console/src/main/js/app/modules/states/configuration/clusters/connector.jade
deleted file mode 100644
index 95f6bb3..0000000
--- a/modules/web-console/src/main/js/app/modules/states/configuration/clusters/connector.jade
+++ /dev/null
@@ -1,103 +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.
-
-include ../../../../../app/helpers/jade/mixins.jade
-
--var form = 'connector'
--var model = 'backupItem.connector'
--var enabled = model + '.enabled'
--var sslEnabled = enabled + ' && ' + model + '.sslEnabled'
-
-form.panel.panel-default(name=form novalidate)
-    .panel-heading(bs-collapse-toggle ng-click='ui.loadPanel("#{form}")')
-        ignite-form-panel-chevron
-        label Connector configuration
-        ignite-form-field-tooltip.tipLabel
-            | REST access configuration
-        ignite-form-revert
-    .panel-collapse(role='tabpanel' bs-collapse-target id=form)
-        .panel-body(ng-if='ui.isPanelLoaded("#{form}")')
-            .col-sm-6
-                .settings-row
-                    +checkbox('Enabled', enabled, 'restEnabled', 'Flag indicating whether to configure connector configuration')
-                .settings-row
-                    +text-enabled('Jetty configuration path:', model + '.jettyPath', 'connectorJettyPath', enabled, 'false', 'Input path to Jetty configuration',
-                        'Path, either absolute or relative to IGNITE_HOME, to Jetty XML configuration file<br/>\
-                        Jetty is used to support REST over HTTP protocol for accessing Ignite APIs remotely<br/>\
-                        If not provided, Jetty instance with default configuration will be started picking IgniteSystemProperties.IGNITE_JETTY_HOST and IgniteSystemProperties.IGNITE_JETTY_PORT as host and port respectively')
-                .settings-row
-                    +text-ip-address('TCP host:', model + '.host', 'connectorHost', enabled, 'IgniteConfiguration#getLocalHost()',
-                        'Host for TCP binary protocol server<br/>\
-                        This can be either an IP address or a domain name<br/>\
-                        If not defined, system - wide local address will be used IgniteConfiguration#getLocalHost()<br/>\
-                        You can also use "0.0.0.0" value to bind to all locally - available IP addresses')
-                .settings-row
-                    +number-min-max('TCP port:', model + '.port', 'connectorPort', enabled, '11211', '1024', '65535', 'Port for TCP binary protocol server')
-                .settings-row
-                    +number('TCP port range:', model + '.portRange', 'connectorPortRange', enabled, '100', '1', 'Number of ports for TCP binary protocol server to try if configured port is already in use')
-                .settings-row
-                    +number('Idle query cursor timeout:', model + '.idleQueryCursorTimeout', 'connectorIdleQueryCursorTimeout', enabled, '600000', '0',
-                        'Reject open query cursors that is not used timeout<br/>\
-                        If no fetch query request come within idle timeout, it will be removed on next check for old query cursors')
-                .settings-row
-                    +number('Idle query cursor check frequency:', model + '.idleQueryCursorCheckFrequency', 'connectorIdleQueryCursorCheckFrequency', enabled, '60000', '0',
-                        'Idle query cursors check frequency<br/>\
-                        This setting is used to reject open query cursors that is not used')
-                .settings-row
-                    +number('Idle timeout:', model + '.idleTimeout', 'connectorIdleTimeout', enabled, '7000', '0',
-                        'Idle timeout for REST server<br/>\
-                        This setting is used to reject half - opened sockets<br/>\
-                        If no packets come within idle timeout, the connection is closed')
-                .settings-row
-                    +number('Receive buffer size:', model + '.receiveBufferSize', 'connectorReceiveBufferSize', enabled, '32768', '0', 'REST TCP server receive buffer size')
-                .settings-row
-                    +number('Send buffer size:', model + '.sendBufferSize', 'connectorSendBufferSize', enabled, '32768', '0', 'REST TCP server send buffer size')
-                .settings-row
-                    +number('Send queue limit:', model + '.sendQueueLimit', 'connectorSendQueueLimit', enabled, 'unlimited', '0',
-                        'REST TCP server send queue limit<br/>\
-                        If the limit exceeds, all successive writes will block until the queue has enough capacity')
-                .settings-row
-                    +checkbox-enabled('Direct buffer', model + '.directBuffer', 'connectorDirectBuffer', enabled,
-                        'Flag indicating whether REST TCP server should use direct buffers<br/>\
-                        A direct buffer is a buffer that is allocated and accessed using native system calls, without using JVM heap<br/>\
-                        Enabling direct buffer may improve performance and avoid memory issues(long GC pauses due to huge buffer size)')
-                .settings-row
-                    +checkbox-enabled('TCP_NODELAY option', model + '.noDelay', 'connectorNoDelay', enabled,
-                        'Flag indicating whether TCP_NODELAY option should be set for accepted client connections<br/>\
-                        Setting this option reduces network latency and should be enabled in majority of cases<br/>\
-                        For more information, see Socket#setTcpNoDelay(boolean)')
-                .settings-row
-                    +number('Selector count:', model + '.selectorCount', 'connectorSelectorCount', enabled, 'min(4, availableProcessors)', '1',
-                        'Number of selector threads in REST TCP server<br/>\
-                        Higher value for this parameter may increase throughput, but also increases context switching')
-                .settings-row
-                    +number('Thread pool size:', model + '.threadPoolSize', 'connectorThreadPoolSize', enabled, 'max(8, availableProcessors) * 2', '1',
-                        'Thread pool size to use for processing of client messages (REST requests)')
-                .settings-row
-                    +java-class('Message interceptor:', model + '.messageInterceptor', 'connectorMessageInterceptor', enabled, 'false',
-                        'Interceptor allows to transform all objects exchanged via REST protocol<br/>\
-                        For example if you use custom serialisation on client you can write interceptor to transform binary representations received from client to Java objects and later access them from java code directly')
-                .settings-row
-                    +text-enabled('Secret key:', model + '.secretKey', 'connectorSecretKey', enabled, 'false', 'Specify to enable authentication', 'Secret key to authenticate REST requests')
-                .settings-row
-                    +checkbox-enabled('Enable SSL', model + '.sslEnabled', 'connectorSslEnabled', enabled, 'Enables/disables SSL for REST TCP binary protocol')
-                .settings-row
-                    +checkbox-enabled('Enable SSL client auth', model + '.sslClientAuth', 'connectorSslClientAuth', sslEnabled, 'Flag indicating whether or not SSL client authentication is required')
-                .settings-row
-                    +java-class('SSL factory:', model + '.sslFactory', 'connectorSslFactory', sslEnabled, sslEnabled,
-                        'Instance of Factory that will be used to create an instance of SSLContext for Secure Socket Layer on TCP binary protocol')
-            .col-sm-6
-                +preview-xml-java(model, 'clusterConnector')

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/src/main/js/app/modules/states/configuration/clusters/deployment.directive.js
----------------------------------------------------------------------
diff --git a/modules/web-console/src/main/js/app/modules/states/configuration/clusters/deployment.directive.js b/modules/web-console/src/main/js/app/modules/states/configuration/clusters/deployment.directive.js
deleted file mode 100644
index 392ed7e..0000000
--- a/modules/web-console/src/main/js/app/modules/states/configuration/clusters/deployment.directive.js
+++ /dev/null
@@ -1,27 +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 templateUrl from './deployment.jade';
-
-export default ['igniteConfigurationClustersDeployment', [() => {
-    return {
-        scope: true,
-        restrict: 'E',
-        templateUrl,
-        replace: true
-    };
-}]];


[14/52] ignite git commit: Web Console beta-3.

Posted by ak...@apache.org.
http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/src/main/js/app/modules/states/configuration/domains/general.jade
----------------------------------------------------------------------
diff --git a/modules/web-console/src/main/js/app/modules/states/configuration/domains/general.jade b/modules/web-console/src/main/js/app/modules/states/configuration/domains/general.jade
deleted file mode 100644
index c7d25b4..0000000
--- a/modules/web-console/src/main/js/app/modules/states/configuration/domains/general.jade
+++ /dev/null
@@ -1,46 +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.
-
-include ../../../../../app/helpers/jade/mixins.jade
-
-- var form = 'general'
-- var model = 'backupItem'
-
-form.panel.panel-default(name=form novalidate)
-    .panel-heading(bs-collapse-toggle)
-        ignite-form-panel-chevron
-        label General
-        ignite-form-field-tooltip.tipLabel
-            | Domain model properties common for Query and Store
-        ignite-form-revert
-    .panel-collapse(role='tabpanel' bs-collapse-target id=form)
-        .panel-body
-            .col-sm-6
-                .settings-row
-                    +caches(model, 'Select caches to associate domain model with cache')
-                .settings-row
-                    +dropdown-required('Query metadata:', model + '.queryMetadata', 'queryMetadata', 'true', 'true', '', 'queryMetadataVariants',
-                        'Query metadata configured with:\
-                        <ul>\
-                            <li>Java annotations like @QuerySqlField</li>\
-                            <li>Configuration via QueryEntity class</li>\
-                        </ul>')
-                .settings-row
-                    +java-class-typeahead('Key type:', model + '.keyType', 'keyType', 'javaBuiltInClasses', 'true', 'true', 'Full class name for Key', 'Key class used to store key in cache')
-                .settings-row
-                    +java-class('Value type:', model + '.valueType', 'valueType', 'true', 'true', 'Value class used to store value in cache')
-            .col-sm-6
-                +preview-xml-java(model, 'domainModelGeneral')

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/src/main/js/app/modules/states/configuration/domains/query.directive.js
----------------------------------------------------------------------
diff --git a/modules/web-console/src/main/js/app/modules/states/configuration/domains/query.directive.js b/modules/web-console/src/main/js/app/modules/states/configuration/domains/query.directive.js
deleted file mode 100644
index 2033394..0000000
--- a/modules/web-console/src/main/js/app/modules/states/configuration/domains/query.directive.js
+++ /dev/null
@@ -1,27 +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 templateUrl from './query.jade';
-
-export default ['igniteConfigurationDomainsQuery', [() => {
-    return {
-        scope: true,
-        restrict: 'E',
-        templateUrl,
-        replace: true
-    };
-}]];

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/src/main/js/app/modules/states/configuration/domains/query.jade
----------------------------------------------------------------------
diff --git a/modules/web-console/src/main/js/app/modules/states/configuration/domains/query.jade b/modules/web-console/src/main/js/app/modules/states/configuration/domains/query.jade
deleted file mode 100644
index 9ac0d00..0000000
--- a/modules/web-console/src/main/js/app/modules/states/configuration/domains/query.jade
+++ /dev/null
@@ -1,169 +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.
-
-include ../../../../../app/helpers/jade/mixins.jade
-
-- var model = 'backupItem'
-- var queryFields = model + '.fields'
-- var queryAliases = model + '.aliases'
-- var queryIndexes = model + '.indexes'
-- var queryFieldsForm = 'queryFields'
-- var queryAliasesForm = 'queryAliases'
-- var queryIndexesForm = 'queryIndexes'
-
-// LEGACY mixin for LEGACY index fields table.
-mixin table-index-item-edit(prefix, index, sortAvailable, idAddition)
-    -var fieldName = prefix + 'FieldName'
-    -var direction = prefix + 'Direction'
-
-    -var fieldNameModel = 'indexesTbl.' + fieldName
-    -var directionModel = 'indexesTbl.' + direction
-
-    -var btnVisible = 'tableIndexItemSaveVisible(indexesTbl, ' + index + ')'
-    -var btnSave = 'tableIndexItemSave(indexesTbl, itemIndex, ' + index + ')'
-    -var btnVisibleAndSave = btnVisible + ' && ' + btnSave
-
-    .col-xs-8.col-sm-8.col-md-8(ng-show=sortAvailable)
-        label.fieldSep /
-        .input-tip
-            input.form-control(id='{{::"#{fieldName}S" + #{idAddition}}}' ignite-on-enter-focus-move='{{::"#{direction}S" + #{idAddition}}}' type='text' ng-model=fieldNameModel placeholder='Field name' ignite-on-escape='tableReset()')
-    .col-xs-4.col-sm-4.col-md-4(ng-show=sortAvailable)
-        +btn-save(btnVisible, btnSave)
-        .input-tip
-            button.select-toggle.form-control(id='{{::"#{direction}S" + #{idAddition}}}' ng-model=directionModel bs-select bs-options='item.value as item.label for item in {{sortDirections}}' ignite-on-enter=btnVisibleAndSave ignite-on-escape='tableReset()' tabindex='0')
-    .col-xs-12(ng-show='!(#{sortAvailable})')
-        +btn-save(btnVisible, btnSave)
-        .input-tip
-            input.form-control(id='{{::"#{fieldName}" + #{idAddition}}}' type='text' ng-model=fieldNameModel placeholder='Field name' ignite-on-enter=btnVisibleAndSave ignite-on-escape='tableReset()')
-
-form.panel.panel-default(name='query' novalidate)
-    .panel-heading(bs-collapse-toggle)
-        ignite-form-panel-chevron
-        label(id='query-title') Domain model for SQL query
-        ignite-form-field-tooltip.tipLabel
-            | Domain model properties for fields queries
-        ignite-form-revert
-    .panel-collapse(role='tabpanel' bs-collapse-target id='query')
-        .panel-body
-            .col-sm-6
-                .content-not-available(ng-if='#{model}.queryMetadata === "Annotations"')
-                    label Not available for annotated types
-                div(ng-if='#{model}.queryMetadata === "Configuration"')
-                    .settings-row
-                        ignite-form-group(ng-model='#{queryFields}' ng-form='#{queryFieldsForm}')
-                            ignite-form-field-label(id='queryFields')
-                                | Fields
-                            ignite-form-group-tooltip
-                                | Collection of name-to-type mappings to be queried, in addition to indexed fields
-                            ignite-form-group-add(ng-click='tableNewItem(queryFieldsTbl)')
-                                | Add field to query
-                            .group-content-empty(ng-if='!((#{queryFields} && #{queryFields}.length > 0) || tableNewItemActive(queryFieldsTbl))')
-                                | Not defined
-                            .group-content(ng-show='(#{queryFields} && #{queryFields}.length > 0) || tableNewItemActive(queryFieldsTbl)')
-                                table.links-edit(id='fields' st-table=queryFields)
-                                    tbody
-                                        tr(ng-repeat='item in #{queryFields}')
-                                            td.col-sm-12(ng-show='!tableEditing(queryFieldsTbl, $index)')
-                                                a.labelFormField(ng-click='tableStartEdit(backupItem, queryFieldsTbl, $index)') {{item.name}}  / {{item.className}}
-                                                +btn-remove('tableRemove(backupItem, queryFieldsTbl, $index)', '"Remove path"')
-                                            td.col-sm-12(ng-show='tableEditing(queryFieldsTbl, $index)')
-                                                +table-pair-edit('queryFieldsTbl', 'cur', 'Field name', 'Field full class name', false, true, '{{::queryFieldsTbl.focusId + $index}}', '$index', '/')
-                                    tfoot(ng-show='tableNewItemActive(queryFieldsTbl)')
-                                        tr
-                                            td.col-sm-12
-                                                +table-pair-edit('queryFieldsTbl', 'new', 'Field name', 'Field full class name', false, true, '{{::queryFieldsTbl.focusId + $index}}', '-1', '/')
-                    .settings-row
-                        ignite-form-group(ng-model='#{queryAliases}' ng-form='#{queryAliasesForm}')
-                            ignite-form-field-label
-                                | Aliases
-                            ignite-form-group-tooltip
-                                | Mapping from full property name in dot notation to an alias that will be used as SQL column name
-                                | For example: "parent.name" as "parentName"
-                            ignite-form-group-add(ng-click='tableNewItem(aliasesTbl)')
-                                | Add alias to query
-                            .group-content-empty(ng-if='!((#{queryAliases} && #{queryAliases}.length > 0) || tableNewItemActive(aliasesTbl))')
-                                | Not defined
-                            .group-content(ng-show='(#{queryAliases} && #{queryAliases}.length > 0) || tableNewItemActive(aliasesTbl)')
-                                table.links-edit(id='aliases' st-table=queryAliases)
-                                    tbody
-                                        tr(ng-repeat='item in #{queryAliases}')
-                                            td.col-sm-12(ng-show='!tableEditing(aliasesTbl, $index)')
-                                                a.labelFormField(ng-click='tableStartEdit(backupItem, aliasesTbl, $index)') {{item.field}} &rarr; {{item.alias}}
-                                                +btn-remove('tableRemove(backupItem, aliasesTbl, $index)', '"Remove alias"')
-                                            td.col-sm-12(ng-show='tableEditing(aliasesTbl, $index)')
-                                                +table-pair-edit('aliasesTbl', 'cur', 'Field name', 'Field Alias', false, false, '{{::aliasesTbl.focusId + $index}}', '$index', '&rarr;')
-                                    tfoot(ng-show='tableNewItemActive(aliasesTbl)')
-                                        tr
-                                            td.col-sm-12
-                                                +table-pair-edit('aliasesTbl', 'new', 'Field name', 'Field Alias', false, false, '{{::aliasesTbl.focusId + $index}}', '-1', '&rarr;')
-                    .settings-row(ng-init='indexesTbl={type: "table-indexes", model: "indexes", focusId: "IndexName", ui: "table-indexes"}')
-                        ignite-form-group(ng-model='#{queryIndexes}' ng-form='#{queryIndexesForm}')
-                            ignite-form-field-label
-                                | Indexes
-                            ignite-form-group-tooltip
-                                | Collection of indexes
-                            ignite-form-group-add(ng-click='tableNewItem(indexesTbl)')
-                                | Add new index
-                            .group-content-empty(id='indexes-add' ng-show='!((#{queryIndexes} && #{queryIndexes}.length > 0) || tableNewItemActive(indexesTbl))')
-                                | Not defined
-                            .group-content(ng-show='(#{queryIndexes} && #{queryIndexes}.length > 0) || tableNewItemActive(indexesTbl)')
-                                -var btnVisibleAndSave = 'tableIndexSaveVisible(indexesTbl, $index) && tableIndexSave(indexesTbl, $index)'
-
-                                table.links-edit(st-table=queryIndexes ng-init='newDirection = false')
-                                    tbody
-                                        tr(ng-repeat='item in #{queryIndexes}')
-                                            td
-                                                .col-sm-12(ng-show='!tableEditing(indexesTbl, $index)')
-                                                    a.labelFormField(id='indexes{{$index}}' ng-click='tableStartEdit(backupItem, indexesTbl, $index)') {{$index + 1}}) {{item.name}} [{{item.indexType}}]
-                                                    +btn-remove('tableRemove(backupItem, indexesTbl, $index)', '"Remove index"')
-                                                    +btn-add('tableIndexNewItem(indexesTbl, $index)', '"Add new field to index"')
-                                                div(ng-show='tableEditing(indexesTbl, $index)')
-                                                    .col-sm-7
-                                                        label.fieldSep /
-                                                        .input-tip
-                                                            input.form-control(id='curIndexName{{$index}}' type='text' ignite-on-enter-focus-move='curIndexType{{$index}}' ng-model='indexesTbl.curIndexName' placeholder='Index name' ignite-on-enter=btnVisibleAndSave ignite-on-escape='tableReset()')
-                                                    .col-sm-5
-                                                        +btn-save('tableIndexSaveVisible(indexesTbl, $index)', 'tableIndexSave(indexesTbl, $index)')
-                                                        .input-tip
-                                                            button.select-toggle.form-control(id='curIndexType{{$index}}' bs-select ng-model='indexesTbl.curIndexType' data-placeholder='Select index type' bs-options='item.value as item.label for item in indexType' tabindex='0' ignite-on-enter=btnVisibleAndSave ignite-on-escape='tableReset()')
-                                                .margin-left-dflt
-                                                    table.links-edit-sub(st-table='item.fields' ng-init='itemIndex = $index')
-                                                        tbody
-                                                            tr(ng-repeat='itemItem in item.fields')
-                                                                td
-                                                                    div(ng-show='!tableIndexItemEditing(indexesTbl, itemIndex, $index)')
-                                                                        a.labelFormField(ng-if='item.indexType == "SORTED"' ng-click='tableIndexItemStartEdit(indexesTbl, itemIndex, $index)') {{$index + 1}}) {{itemItem.name}} / {{itemItem.direction ? "ASC" : "DESC"}}
-                                                                        a.labelFormField(ng-if='item.indexType != "SORTED"' ng-click='tableIndexItemStartEdit(indexesTbl, itemIndex, $index)') {{$index + 1}}) {{itemItem.name}}
-                                                                        +btn-remove('tableRemoveIndexItem(item, $index)', '"Remove field from index"')
-                                                                    div(ng-show='tableIndexItemEditing(indexesTbl, itemIndex, $index)')
-                                                                        +table-index-item-edit('cur', '$index', 'item.indexType == "SORTED"', 'itemIndex + "-" + $index')
-                                                        tfoot(ng-show='tableIndexNewItemActive(indexesTbl, itemIndex)')
-                                                            tr(style='padding-left: 18px')
-                                                                td
-                                                                    +table-index-item-edit('new', '-1', 'item.indexType == "SORTED"', 'itemIndex')
-                                    tfoot(ng-show='tableNewItemActive(indexesTbl)')
-                                        tr
-                                            td
-                                                .col-sm-7
-                                                    .fieldSep /
-                                                    .input-tip
-                                                        input#newIndexName.form-control(type='text' ignite-on-enter-focus-move='newIndexType' ng-model='indexesTbl.newIndexName' placeholder='Index name' ignite-on-enter='tableIndexSaveVisible(indexesTbl, -1) && tableIndexSave(indexesTbl, -1)' ignite-on-escape='tableReset()')
-                                                .col-sm-5
-                                                    +btn-save('tableIndexSaveVisible(indexesTbl, -1)', 'tableIndexSave(indexesTbl, -1)')
-                                                    .input-tip
-                                                        button#newIndexType.select-toggle.form-control(bs-select ng-model='indexesTbl.newIndexType' data-placeholder='Select index type' bs-options='item.value as item.label for item in indexType' tabindex='0' ignite-on-enter=btnVisibleAndSave ignite-on-escape='tableReset()')
-            .col-sm-6
-                +preview-xml-java(model, 'domainModelQuery')

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/src/main/js/app/modules/states/configuration/domains/store.directive.js
----------------------------------------------------------------------
diff --git a/modules/web-console/src/main/js/app/modules/states/configuration/domains/store.directive.js b/modules/web-console/src/main/js/app/modules/states/configuration/domains/store.directive.js
deleted file mode 100644
index a69b025..0000000
--- a/modules/web-console/src/main/js/app/modules/states/configuration/domains/store.directive.js
+++ /dev/null
@@ -1,27 +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 templateUrl from './store.jade';
-
-export default ['igniteConfigurationDomainsStore', [() => {
-    return {
-        scope: true,
-        restrict: 'E',
-        templateUrl,
-        replace: true
-    };
-}]];

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/src/main/js/app/modules/states/configuration/domains/store.jade
----------------------------------------------------------------------
diff --git a/modules/web-console/src/main/js/app/modules/states/configuration/domains/store.jade b/modules/web-console/src/main/js/app/modules/states/configuration/domains/store.jade
deleted file mode 100644
index 8d3c65b..0000000
--- a/modules/web-console/src/main/js/app/modules/states/configuration/domains/store.jade
+++ /dev/null
@@ -1,126 +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.
-
-include ../../../../../app/helpers/jade/mixins.jade
-
--var form = 'store'
--var model = 'backupItem'
--var keyFields = model + '.keyFields'
--var valueFields = model + '.valueFields'
--var keyFieldsForm = 'storeKeyFields'
--var valueFieldsForm = 'storeValueFields'
-
-//- LEGACY mixin for LEGACY db fields tables.
-mixin table-db-field-edit(tbl, prefix, focusId, index)
-    -var databaseName = prefix + 'DatabaseFieldName'
-    -var databaseType = prefix + 'DatabaseFieldType'
-    -var javaName = prefix + 'JavaFieldName'
-    -var javaType = prefix + 'JavaFieldType'
-
-    -var databaseNameModel = tbl + '.' + databaseName
-    -var databaseTypeModel = tbl + '.' + databaseType
-    -var javaNameModel = tbl + '.' + javaName
-    -var javaTypeModel = tbl + '.' + javaType
-
-    -var databaseNameId = databaseName + focusId
-    -var databaseTypeId = databaseType + focusId
-    -var javaNameId = javaName + focusId
-    -var javaTypeId = javaType + focusId
-
-    .col-xs-3.col-sm-3.col-md-3
-        .fieldSep /
-        .input-tip
-            input.form-control(id=databaseNameId ignite-on-enter-focus-move=databaseTypeId type='text' ng-model=databaseNameModel placeholder='DB name' ignite-on-enter='#{javaNameModel} = #{javaNameModel} ? #{javaNameModel} : #{databaseNameModel}' ignite-on-escape='tableReset()')
-    .col-xs-3.col-sm-3.col-md-3
-        .fieldSep /
-        .input-tip
-            button.select-toggle.form-control(id=databaseTypeId ignite-on-enter-focus-move=javaNameId ng-model=databaseTypeModel data-placeholder='DB type' ng-class='{placeholder: !#{databaseTypeModel}}' bs-select bs-options='item.value as item.label for item in {{supportedJdbcTypes}}' ignite-on-escape='tableReset()' tabindex='0')
-    .col-xs-3.col-sm-3.col-md-3
-        .fieldSep /
-        .input-tip
-            input.form-control(id=javaNameId ignite-on-enter-focus-move=javaTypeId type='text' ng-model=javaNameModel placeholder='Java name' ignite-on-escape='tableReset()')
-    .col-xs-3.col-sm-3.col-md-3
-        -var btnVisible = 'tableDbFieldSaveVisible(' + tbl + ', ' + index +')'
-        -var btnSave = 'tableDbFieldSave(' + tbl + ', ' + index +')'
-        -var btnVisibleAndSave = btnVisible + ' && ' + btnSave
-
-        +btn-save(btnVisible, btnSave)
-        .input-tip
-            button.select-toggle.form-control(id=javaTypeId ng-model=javaTypeModel data-placeholder='Java type' ng-class='{placeholder: !#{javaTypeModel}}' bs-select bs-options='item.value as item.label for item in {{supportedJavaTypes}}' ignite-on-enter=btnVisibleAndSave ignite-on-escape='tableReset()' tabindex='0')
-
-form.panel.panel-default(name=form novalidate)
-    .panel-heading(bs-collapse-toggle='' ng-click='ui.loadPanel("#{form}")')
-        ignite-form-panel-chevron
-        label Domain model for cache store
-        ignite-form-field-tooltip.tipLabel
-            | Domain model properties for binding database with cache via POJO cache store
-        ignite-form-revert
-    .panel-collapse(role='tabpanel' bs-collapse-target id=form)
-        .panel-body(ng-if='ui.isPanelLoaded("#{form}")')
-            .col-sm-6
-                .settings-row
-                    +text('Database schema:', model + '.databaseSchema', 'databaseSchema', 'false', 'Input DB schema name', 'Schema name in database')
-                .settings-row
-                    +text('Database table:', model + '.databaseTable', 'databaseTable', 'false', 'Input DB table name', 'Table name in database')
-                .settings-row(ng-init='keysTbl={type: "table-db-fields", model: "keyFields", focusId: "KeyField", ui: "table-db-fields"}')
-                    ignite-form-group(ng-model='#{keyFields}' ng-form='#{keyFieldsForm}')
-                        ignite-form-field-label(id='keyFields')
-                            | Key fields
-                        ignite-form-group-tooltip
-                            | Collection of key fields descriptions for CacheJdbcPojoStore
-                        ignite-form-group-add(ng-click='tableNewItem(keysTbl)')
-                            | Add key field
-                        .group-content-empty(ng-show='!((#{keyFields} && #{keyFields}.length > 0) || tableNewItemActive(keysTbl))') Not defined
-                        .group-content(ng-show='(#{keyFields} && #{keyFields}.length > 0) || tableNewItemActive(keysTbl)')
-                            table.links-edit(st-table=keyFields)
-                                tbody
-                                    tr(ng-repeat='item in #{keyFields}')
-                                        td
-                                            div(ng-show='!tableEditing(keysTbl, $index)')
-                                                a.labelFormField(ng-click='tableStartEdit(backupItem, keysTbl, $index)') {{$index + 1}}) {{item.databaseFieldName}} / {{item.databaseFieldType}} / {{item.javaFieldName}} / {{item.javaFieldType}}
-                                                +btn-remove('tableRemove(backupItem, keysTbl, $index)', '"Remove key field"')
-                                            div(ng-show='tableEditing(keysTbl, $index)')
-                                                +table-db-field-edit('keysTbl', 'cur', '{{::keysTbl.focusId + $index}}', '$index')
-                                tfoot(ng-show='tableNewItemActive(keysTbl)')
-                                    tr
-                                        td
-                                            +table-db-field-edit('keysTbl', 'new', 'KeyField', '-1')
-                .settings-row(ng-init='valuesTbl={type: "table-db-fields", model: "valueFields", focusId: "ValueField", ui: "table-db-fields"}')
-                    ignite-form-group(ng-model='#{valueFields}' ng-form='#{valueFieldsForm}')
-                        ignite-form-field-label(id='valueFields')
-                            | Value fields
-                        ignite-form-group-tooltip
-                            | Collection of value fields descriptions for CacheJdbcPojoStore
-                        ignite-form-group-add(ng-click='tableNewItem(valuesTbl)')
-                            | Add value field
-                        .group-content-empty(ng-show='!((#{valueFields} && #{valueFields}.length > 0) || tableNewItemActive(valuesTbl))') Not defined
-                        .group-content(ng-show='(#{valueFields} && #{valueFields}.length > 0) || tableNewItemActive(valuesTbl)')
-                            table.links-edit(st-table=valueFields)
-                                tbody
-                                    tr(ng-repeat='item in #{valueFields}')
-                                        td
-                                            div(ng-show='!tableEditing(valuesTbl, $index)')
-                                                a.labelFormField(ng-click='tableStartEdit(backupItem, valuesTbl, $index)') {{$index + 1}}) {{item.databaseFieldName}} / {{item.databaseFieldType}} / {{item.javaFieldName}} / {{item.javaFieldType}}
-                                                +btn-remove('tableRemove(backupItem, valuesTbl, $index)', '"Remove key field"')
-                                            div(ng-show='tableEditing(valuesTbl, $index)')
-                                                +table-db-field-edit('valuesTbl', 'cur', '{{::valuesTbl.focusId + $index}}', '$index')
-                                tfoot(ng-show='tableNewItemActive(valuesTbl)')
-                                    tr
-                                        td
-                                            +table-db-field-edit('valuesTbl', 'new', 'ValueField', '-1')
-            .col-sm-6
-                +preview-xml-java(model, 'domainStore')
-

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/src/main/js/app/modules/states/configuration/igfs/dual.directive.js
----------------------------------------------------------------------
diff --git a/modules/web-console/src/main/js/app/modules/states/configuration/igfs/dual.directive.js b/modules/web-console/src/main/js/app/modules/states/configuration/igfs/dual.directive.js
deleted file mode 100644
index c5afc4e..0000000
--- a/modules/web-console/src/main/js/app/modules/states/configuration/igfs/dual.directive.js
+++ /dev/null
@@ -1,27 +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 templateUrl from './dual.jade';
-
-export default ['igniteConfigurationIgfsDual', [() => {
-    return {
-        scope: true,
-        restrict: 'E',
-        templateUrl,
-        replace: true
-    };
-}]];

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/src/main/js/app/modules/states/configuration/igfs/dual.jade
----------------------------------------------------------------------
diff --git a/modules/web-console/src/main/js/app/modules/states/configuration/igfs/dual.jade b/modules/web-console/src/main/js/app/modules/states/configuration/igfs/dual.jade
deleted file mode 100644
index 8129f0d..0000000
--- a/modules/web-console/src/main/js/app/modules/states/configuration/igfs/dual.jade
+++ /dev/null
@@ -1,42 +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.
-
-include ../../../../../app/helpers/jade/mixins.jade
-
--var form = 'dualMode'
--var model = 'backupItem'
-
-form.panel.panel-default(name=form novalidate)
-    .panel-heading(bs-collapse-toggle='' ng-click='ui.loadPanel("#{form}")')
-        ignite-form-panel-chevron
-        label Dual mode
-        ignite-form-field-tooltip.tipLabel
-            | IGFS supports dual-mode that allows it to work as either a standalone file system in Hadoop cluster, or work in tandem with HDFS, providing a primary caching layer for the secondary HDFS#[br]
-            | As a caching layer it provides highly configurable read-through and write-through behaviour
-        ignite-form-revert
-    .panel-collapse(role='tabpanel' bs-collapse-target id=form)
-        .panel-body(ng-if='ui.isPanelLoaded("#{form}")')
-            .col-sm-6
-                .settings-row
-                    +number('Maximum pending puts size:', model + '.dualModeMaxPendingPutsSize', 'dualModeMaxPendingPutsSize', 'true', '0', 'Number.MIN_SAFE_INTEGER',
-                        'Maximum amount of pending data read from the secondary file system and waiting to be written to data cache<br/>\
-                        Zero or negative value stands for unlimited size')
-                .settings-row
-                    +java-class('Put executor service:', model + '.dualModePutExecutorService', 'dualModePutExecutorService', 'true', 'false', 'DUAL mode put operation executor service')
-                .settings-row
-                    +checkbox('Put executor service shutdown', model + '.dualModePutExecutorServiceShutdown', 'dualModePutExecutorServiceShutdown', 'DUAL mode put operation executor service shutdown flag')
-            .col-sm-6
-                +preview-xml-java(model, 'igfsDualMode')

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/src/main/js/app/modules/states/configuration/igfs/fragmentizer.directive.js
----------------------------------------------------------------------
diff --git a/modules/web-console/src/main/js/app/modules/states/configuration/igfs/fragmentizer.directive.js b/modules/web-console/src/main/js/app/modules/states/configuration/igfs/fragmentizer.directive.js
deleted file mode 100644
index d008933..0000000
--- a/modules/web-console/src/main/js/app/modules/states/configuration/igfs/fragmentizer.directive.js
+++ /dev/null
@@ -1,27 +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 templateUrl from './fragmentizer.jade';
-
-export default ['igniteConfigurationIgfsFragmentizer', [() => {
-    return {
-        scope: true,
-        restrict: 'E',
-        templateUrl,
-        replace: true
-    };
-}]];

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/src/main/js/app/modules/states/configuration/igfs/fragmentizer.jade
----------------------------------------------------------------------
diff --git a/modules/web-console/src/main/js/app/modules/states/configuration/igfs/fragmentizer.jade b/modules/web-console/src/main/js/app/modules/states/configuration/igfs/fragmentizer.jade
deleted file mode 100644
index fa8c244..0000000
--- a/modules/web-console/src/main/js/app/modules/states/configuration/igfs/fragmentizer.jade
+++ /dev/null
@@ -1,43 +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.
-
-include ../../../../../app/helpers/jade/mixins.jade
-
--var form = 'fragmentizer'
--var model = 'backupItem'
-
-form.panel.panel-default(name=form novalidate)
-    .panel-heading(bs-collapse-toggle='' ng-click='ui.loadPanel("#{form}")')
-        ignite-form-panel-chevron
-        label Fragmentizer
-        ignite-form-field-tooltip.tipLabel
-            | Fragmentizer settings
-        ignite-form-revert
-    .panel-collapse(role='tabpanel' bs-collapse-target id=form)
-        .panel-body(ng-if='ui.isPanelLoaded("#{form}")')
-            .col-sm-6
-                -var enabled = model + '.fragmentizerEnabled'
-
-                .settings-row
-                    +checkbox('Enabled', enabled, 'fragmentizerEnabled', 'Fragmentizer enabled flag')
-                .settings-row
-                    +number('Concurrent files:', model + '.fragmentizerConcurrentFiles', 'fragmentizerConcurrentFiles', enabled, '0', '0', 'Number of files to process concurrently by fragmentizer')
-                .settings-row
-                    +number('Throttling block length:', model + '.fragmentizerThrottlingBlockLength', 'fragmentizerThrottlingBlockLength', enabled, '16777216', '1', 'Length of file chunk to transmit before throttling is delayed')
-                .settings-row
-                    +number('Throttling delay:', model + '.fragmentizerThrottlingDelay', 'fragmentizerThrottlingDelay', enabled, '200', '0', 'Delay in milliseconds for which fragmentizer is paused')
-            .col-sm-6
-                +preview-xml-java(model, 'igfsFragmentizer')

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/src/main/js/app/modules/states/configuration/igfs/general.directive.js
----------------------------------------------------------------------
diff --git a/modules/web-console/src/main/js/app/modules/states/configuration/igfs/general.directive.js b/modules/web-console/src/main/js/app/modules/states/configuration/igfs/general.directive.js
deleted file mode 100644
index bda5418..0000000
--- a/modules/web-console/src/main/js/app/modules/states/configuration/igfs/general.directive.js
+++ /dev/null
@@ -1,27 +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 templateUrl from './general.jade';
-
-export default ['igniteConfigurationIgfsGeneral', [() => {
-    return {
-        scope: true,
-        restrict: 'E',
-        templateUrl,
-        replace: true
-    };
-}]];

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/src/main/js/app/modules/states/configuration/igfs/general.jade
----------------------------------------------------------------------
diff --git a/modules/web-console/src/main/js/app/modules/states/configuration/igfs/general.jade b/modules/web-console/src/main/js/app/modules/states/configuration/igfs/general.jade
deleted file mode 100644
index e81dd9b..0000000
--- a/modules/web-console/src/main/js/app/modules/states/configuration/igfs/general.jade
+++ /dev/null
@@ -1,53 +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.
-
-include ../../../../../app/helpers/jade/mixins.jade
-
--var model = 'backupItem'
-
-form.panel.panel-default(name='general' novalidate)
-    .panel-heading(bs-collapse-toggle)
-        ignite-form-panel-chevron
-        label General
-        ignite-form-revert
-    .panel-collapse(role='tabpanel' bs-collapse-target id='general')
-        .panel-body
-            .col-sm-6
-                .settings-row
-                    +text('Name:', model + '.name', 'igfsName', 'true', 'Input name', 'IGFS name')
-                .settings-row
-                    +clusters(model, 'Associate clusters with the current IGFS')
-                .settings-row
-                    +dropdown('IGFS mode:', model + '.defaultMode', 'defaultMode', 'true', 'DUAL_ASYNC',
-                    '[\
-                        {value: "PRIMARY", label: "PRIMARY"},\
-                        {value: "PROXY", label: "PROXY"},\
-                        {value: "DUAL_SYNC", label: "DUAL_SYNC"},\
-                        {value: "DUAL_ASYNC", label: "DUAL_ASYNC"}\
-                    ]',
-                    'Mode to specify how IGFS interacts with Hadoop file system:\
-                    <ul>\
-                        <li>PRIMARY - in this mode IGFS will not delegate to secondary Hadoop file system and will cache all the files in memory only</li>\
-                        <li>PROXY - in this mode IGFS will not cache any files in memory and will only pass them through to secondary file system</li>\
-                        <li>DUAL_SYNC - in this mode IGFS will cache files locally and also <b>synchronously</b> write them through to secondary file system</li>\
-                        <li>DUAL_ASYNC - in this mode IGFS will cache files locally and also <b> asynchronously </b> write them through to secondary file system</li>\
-                    </ul>')
-                .settings-row
-                    +number('Group size:', model + '.affinnityGroupSize', 'affinnityGroupSize', 'true', '512', '1',
-                        'Size of the group in blocks<br/>\
-                        Required for construction of affinity mapper in IGFS data cache')
-            .col-sm-6
-                +preview-xml-java(model, 'igfsGeneral')

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/src/main/js/app/modules/states/configuration/igfs/ipc.directive.js
----------------------------------------------------------------------
diff --git a/modules/web-console/src/main/js/app/modules/states/configuration/igfs/ipc.directive.js b/modules/web-console/src/main/js/app/modules/states/configuration/igfs/ipc.directive.js
deleted file mode 100644
index eb52e51..0000000
--- a/modules/web-console/src/main/js/app/modules/states/configuration/igfs/ipc.directive.js
+++ /dev/null
@@ -1,27 +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 templateUrl from './ipc.jade';
-
-export default ['igniteConfigurationIgfsIpc', [() => {
-    return {
-        scope: true,
-        restrict: 'E',
-        templateUrl,
-        replace: true
-    };
-}]];

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/src/main/js/app/modules/states/configuration/igfs/ipc.jade
----------------------------------------------------------------------
diff --git a/modules/web-console/src/main/js/app/modules/states/configuration/igfs/ipc.jade b/modules/web-console/src/main/js/app/modules/states/configuration/igfs/ipc.jade
deleted file mode 100644
index 361036a..0000000
--- a/modules/web-console/src/main/js/app/modules/states/configuration/igfs/ipc.jade
+++ /dev/null
@@ -1,57 +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.
-
-include ../../../../../app/helpers/jade/mixins.jade
-
--var form = 'ipc'
--var model = 'backupItem'
-
-form.panel.panel-default(name=form novalidate)
-    .panel-heading(bs-collapse-toggle='' ng-click='ui.loadPanel("#{form}")')
-        ignite-form-panel-chevron
-        label IPC
-        ignite-form-field-tooltip.tipLabel
-            | IGFS Inter-process communication properties
-        ignite-form-revert
-    .panel-collapse(role='tabpanel' bs-collapse-target id=form)
-        .panel-body(ng-if='ui.isPanelLoaded("#{form}")')
-            .col-sm-6
-                -var ipcEndpointConfiguration = model + '.ipcEndpointConfiguration'
-                -var enabled = model + '.ipcEndpointEnabled'
-
-                .settings-row
-                    +checkbox('Enabled', enabled, 'ipcEndpointEnabled', 'IPC endpoint enabled flag')
-                .settings-row
-                    +dropdown('Type:', ipcEndpointConfiguration + '.type', 'ipcEndpointConfigurationType', enabled, 'TCP',
-                        '[\
-                            {value: "SHMEM", label: "SHMEM"},\
-                            {value: "TCP", label: "TCP"}\
-                        ]',
-                        'IPC endpoint type\
-                        <ul>\
-                            <li>SHMEM - shared memory endpoint</li>\
-                            <li>TCP - TCP endpoint</li>\
-                        </ul>')
-                .settings-row
-                    +text-ip-address('Host:', ipcEndpointConfiguration + '.host', 'ipcEndpointConfigurationHost', enabled, '127.0.0.1', 'Host name')
-                .settings-row
-                    +number-min-max('Port:', ipcEndpointConfiguration + '.port', 'ipcEndpointConfigurationPort', enabled, '10500', '1', '65535', 'Port number')
-                .settings-row
-                    +number('Memory size:', ipcEndpointConfiguration + '.memorySize', 'ipcEndpointConfigurationMemorySize', enabled, '262144', '1', 'Shared memory size in bytes allocated for endpoint communication')
-                .settings-row
-                    +text-enabled('Token directory:', ipcEndpointConfiguration + '.tokenDirectoryPath', 'ipcEndpointConfigurationTokenDirectoryPath', enabled, 'false', 'ipc/shmem', 'Directory where shared memory tokens are stored')
-            .col-sm-6
-                +preview-xml-java(model, 'igfsIPC')

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/src/main/js/app/modules/states/configuration/igfs/misc.directive.js
----------------------------------------------------------------------
diff --git a/modules/web-console/src/main/js/app/modules/states/configuration/igfs/misc.directive.js b/modules/web-console/src/main/js/app/modules/states/configuration/igfs/misc.directive.js
deleted file mode 100644
index 810944f..0000000
--- a/modules/web-console/src/main/js/app/modules/states/configuration/igfs/misc.directive.js
+++ /dev/null
@@ -1,27 +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 templateUrl from './misc.jade';
-
-export default ['igniteConfigurationIgfsMisc', [() => {
-    return {
-        scope: true,
-        restrict: 'E',
-        templateUrl,
-        replace: true
-    };
-}]];

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/src/main/js/app/modules/states/configuration/igfs/misc.jade
----------------------------------------------------------------------
diff --git a/modules/web-console/src/main/js/app/modules/states/configuration/igfs/misc.jade b/modules/web-console/src/main/js/app/modules/states/configuration/igfs/misc.jade
deleted file mode 100644
index dc48d07..0000000
--- a/modules/web-console/src/main/js/app/modules/states/configuration/igfs/misc.jade
+++ /dev/null
@@ -1,108 +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.
-
-include ../../../../../app/helpers/jade/mixins.jade
-
--var form = 'misc'
--var model = 'backupItem'
--var pathModesForm = 'miscPathModes'
--var pathModes = model + '.pathModes'
-
-//- LEGACY mixin for LEGACY IGFS path modes table.
-mixin table-igfs-path-mode-edit(prefix, focusId, index)
-    -var keyModel = 'tblPathModes.' + prefix + 'Key'
-    -var valModel = 'tblPathModes.' + prefix + 'Value'
-
-    -var keyFocusId = prefix + 'Key' + focusId
-    -var valFocusId = prefix + 'Value' + focusId
-
-    .col-xs-8.col-sm-8.col-md-8
-        .fieldSep /
-        .input-tip
-            input.form-control(id=keyFocusId ignite-on-enter-focus-move=valFocusId type='text' ng-model=keyModel placeholder='Path' ignite-on-escape='tableReset()')
-    .col-xs-4.col-sm-4.col-md-4
-        -var arg = keyModel + ', ' + valModel
-        -var btnVisible = 'tablePairSaveVisible(tblPathModes, ' + index + ')'
-        -var btnSave = 'tablePairSave(tablePairValid, backupItem, tblPathModes, ' + index + ')'
-        -var btnVisibleAndSave = btnVisible + ' && ' + btnSave
-        +btn-save(btnVisible, btnSave)
-        .input-tip
-            button.select-toggle.form-control(id=valFocusId bs-select ng-model=valModel data-placeholder='Mode' bs-options='item.value as item.label for item in igfsModes' tabindex='0' ignite-on-enter=btnVisibleAndSave ignite-on-escape='tableReset()')
-
-form.panel.panel-default(name=form novalidate)
-    .panel-heading(bs-collapse-toggle='' ng-click='ui.loadPanel("#{form}")')
-        ignite-form-panel-chevron
-        label Miscellaneous
-        ignite-form-field-tooltip.tipLabel
-            | Various miscellaneous IGFS settings
-        ignite-form-revert
-    .panel-collapse(role='tabpanel' bs-collapse-target id=form)
-        .panel-body(ng-if='ui.isPanelLoaded("#{form}")')
-            .col-sm-6
-                .settings-row
-                    +number('Block size:', model + '.blockSize', 'blockSize', 'true', '65536', '0', 'File data block size in bytes')
-                .settings-row
-                    +number('Stream buffer size:', model + '.streamBufferSize', 'streamBufferSize', 'true', '65536', '0', 'File data block size in bytes')
-                .settings-row
-                    +number('Maximum space size:', model + '.maxSpaceSize', 'maxSpaceSize', 'true', '0', '0', 'Maximum space available for data cache to store file system entries')
-                .settings-row
-                    +number('Maximum task range length:', model + '.maximumTaskRangeLength', 'maximumTaskRangeLength', 'true', '0', '0', 'Maximum default range size of a file being split during IGFS task execution')
-                .settings-row
-                    +number-min-max('Management port:', model + '.managementPort', 'managementPort', 'true', '11400', '0', '65535', 'Port number for management endpoint')
-                .settings-row
-                    +number('Per node batch size:', model + '.perNodeBatchSize', 'perNodeBatchSize', 'true', '100', '0', 'Number of file blocks collected on local node before sending batch to remote node')
-                .settings-row
-                    +number('Per node parallel batch count:', model + '.perNodeParallelBatchCount', 'perNodeParallelBatchCount', 'true', '8', '0', 'Number of file block batches that can be concurrently sent to remote node')
-                .settings-row
-                    +number('Prefetch blocks:', model + '.prefetchBlocks', 'prefetchBlocks', 'true', '0', '0', 'Number of pre-fetched blocks if specific file chunk is requested')
-                .settings-row
-                    +number('Sequential reads before prefetch:', model + '.sequentialReadsBeforePrefetch', 'sequentialReadsBeforePrefetch', 'true', '0', '0', 'Amount of sequential block reads before prefetch is triggered')
-                .settings-row
-                    +number('Trash purge timeout:', model + '.trashPurgeTimeout', 'trashPurgeTimeout', 'true', '1000', '0', 'Maximum timeout awaiting for trash purging in case data cache oversize is detected')
-                .settings-row
-                    +checkbox('Colocate metadata', model + '.colocateMetadata', 'colocateMetadata', 'Whether to co-locate metadata on a single node')
-                .settings-row
-                    +checkbox('Relaxed consistency', model + '.relaxedConsistency', 'relaxedConsistency',
-                        'If value of this flag is <b>true</b>, IGFS will skip expensive consistency checks<br/>\
-                        It is recommended to set this flag to <b>false</b> if your application has conflicting\
-                        operations, or you do not know how exactly users will use your system')
-                .settings-row
-                    ignite-form-group(ng-model=pathModes ng-form=pathModesForm)
-                        ignite-form-field-label
-                            | Path modes
-                        ignite-form-group-tooltip
-                            | Map of path prefixes to IGFS modes used for them
-                        ignite-form-group-add(ng-click='tableNewItem(tblPathModes)')
-                            | Add path mode
-
-                        .group-content-empty(ng-if='!((#{pathModes} && #{pathModes}.length > 0) || tableNewItemActive(tblPathModes))') Not defined
-
-                        .group-content(ng-show='(#{pathModes} && #{pathModes}.length > 0) || tableNewItemActive(tblPathModes)')
-                            table.links-edit(id='pathModes' st-table=pathModes)
-                                tbody
-                                    tr(ng-repeat='item in #{pathModes}')
-                                        td.col-sm-12(ng-show='!tableEditing(tblPathModes, $index)')
-                                            a.labelFormField(ng-click='tableStartEdit(backupItem, tblPathModes, $index)') {{item.path + " [" + item.mode + "]"}}
-                                            +btn-remove('tableRemove(backupItem, tblPathModes, $index)', '"Remove path"')
-                                        td.col-sm-12(ng-show='tableEditing(tblPathModes, $index)')
-                                            +table-igfs-path-mode-edit('cur', '{{::tblPathModes.focusId + $index}}', '$index')
-                                tfoot(ng-show='tableNewItemActive(tblPathModes)')
-                                    tr
-                                        td.col-sm-12
-                                            +table-igfs-path-mode-edit('new', 'PathMode', '-1')
-
-            .col-sm-6
-                +preview-xml-java(model, 'igfsMisc')

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/src/main/js/app/modules/states/configuration/igfs/secondary.directive.js
----------------------------------------------------------------------
diff --git a/modules/web-console/src/main/js/app/modules/states/configuration/igfs/secondary.directive.js b/modules/web-console/src/main/js/app/modules/states/configuration/igfs/secondary.directive.js
deleted file mode 100644
index 69179c0..0000000
--- a/modules/web-console/src/main/js/app/modules/states/configuration/igfs/secondary.directive.js
+++ /dev/null
@@ -1,27 +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 templateUrl from './secondary.jade';
-
-export default ['igniteConfigurationIgfsSecondary', [() => {
-    return {
-        scope: true,
-        restrict: 'E',
-        templateUrl,
-        replace: true
-    };
-}]];

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/src/main/js/app/modules/states/configuration/igfs/secondary.jade
----------------------------------------------------------------------
diff --git a/modules/web-console/src/main/js/app/modules/states/configuration/igfs/secondary.jade b/modules/web-console/src/main/js/app/modules/states/configuration/igfs/secondary.jade
deleted file mode 100644
index 333fad9..0000000
--- a/modules/web-console/src/main/js/app/modules/states/configuration/igfs/secondary.jade
+++ /dev/null
@@ -1,44 +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.
-
-include ../../../../../app/helpers/jade/mixins.jade
-
--var form = 'secondaryFileSystem'
--var model = 'backupItem'
-
-form.panel.panel-default(name=form novalidate)
-    .panel-heading(bs-collapse-toggle='' ng-click='ui.loadPanel("#{form}")')
-        ignite-form-panel-chevron
-        label(id="secondaryFileSystem-title") Secondary file system
-        ignite-form-field-tooltip.tipLabel
-            | Secondary file system is provided for pass-through, write-through, and read-through purposes
-        ignite-form-revert
-    .panel-collapse(role='tabpanel' bs-collapse-target id=form)
-        .panel-body(ng-if='ui.isPanelLoaded("#{form}")')
-            .col-sm-6
-                -var enabled = model + '.secondaryFileSystemEnabled'
-                -var secondaryFileSystem = model + '.secondaryFileSystem'
-
-                .settings-row
-                    +checkbox('Enabled', enabled, 'secondaryFileSystemEnabled', 'Secondary file system enabled flag')
-                .settings-row
-                    +text-enabled('URI:', secondaryFileSystem + '.uri', 'hadoopURI', enabled, 'false', 'hdfs://[namenodehost]:[port]/[path]', 'URI of file system')
-                .settings-row
-                    +text-enabled('Config path:', secondaryFileSystem + '.cfgPath', 'cfgPath', enabled, 'false', 'Path to additional config', 'Additional path to Hadoop configuration')
-                .settings-row
-                    +text-enabled('User name:', secondaryFileSystem + '.userName', 'userName', enabled, 'false', 'Input user name', 'User name')
-            .col-sm-6
-                +preview-xml-java(model, 'igfsSecondFS')

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/src/main/js/app/modules/states/configuration/preview-panel.directive.js
----------------------------------------------------------------------
diff --git a/modules/web-console/src/main/js/app/modules/states/configuration/preview-panel.directive.js b/modules/web-console/src/main/js/app/modules/states/configuration/preview-panel.directive.js
deleted file mode 100644
index be7bf1e..0000000
--- a/modules/web-console/src/main/js/app/modules/states/configuration/preview-panel.directive.js
+++ /dev/null
@@ -1,239 +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 ace from 'brace';
-
-export default ['previewPanel', ['$interval', '$timeout', ($interval, $timeout) => {
-    let animation = {editor: null, stage: 0, start: 0, stop: 0};
-    let prevContent = [];
-
-    const Range = ace.acequire('ace/range').Range;
-
-    const _clearSelection = (editor) => {
-        _.forEach(editor.session.getMarkers(false), (marker) => {
-            editor.session.removeMarker(marker.id);
-        });
-    };
-
-    /**
-     * Switch to next stage of animation.
-     */
-    const _animate = () => {
-        animation.stage += animation.step;
-
-        const stage = animation.stage;
-        const editor = animation.editor;
-
-        _clearSelection(editor);
-
-        animation.selections.forEach((selection) => {
-            editor.session.addMarker(new Range(selection.start, 0, selection.stop, 0),
-                'preview-highlight-' + stage, 'line', false);
-        });
-
-        if (stage === animation.finalStage) {
-            editor.animatePromise = null;
-
-            if (animation.clearOnFinal)
-                _clearSelection(editor);
-        }
-    };
-
-    /**
-     * Selection with animation.
-     *
-     * @param editor Editor to show selection animation.
-     * @param selections Array of selection intervals.
-     * @param step Step of animation (1 or -1).
-     * @param stage Start stage of animation.
-     * @param finalStage Final stage of animation.
-     * @param clearOnFinal Boolean flat to clear selection on animation finish.
-     */
-    const _fade = (editor, selections, step, stage, finalStage, clearOnFinal) => {
-        const promise = editor.animatePromise;
-
-        if (promise) {
-            $interval.cancel(promise);
-
-            _clearSelection(editor);
-        }
-
-        animation = {editor, selections, step, stage, finalStage, clearOnFinal};
-
-        editor.animatePromise = $interval(_animate, 100, 10, false);
-    };
-
-    /**
-     * Show selections with animation.
-     *
-     * @param editor Editor to show selection.
-     * @param selections Array of selection intervals.
-     */
-    const _fadeIn = (editor, selections) => {
-        _fade(editor, selections, 1, 0, 10, false);
-    };
-
-    /**
-     * Hide selections with animation.
-     *
-     * @param editor Editor to show selection.
-     * @param selections Array of selection intervals.
-     */
-    const _fadeOut = (editor, selections) => {
-        _fade(editor, selections, -1, 10, 0, true);
-    };
-
-    const onChange = ([content, editor]) => {
-        const {clearPromise} = editor;
-        const {lines} = content;
-
-        if (content.action === 'remove')
-            prevContent = lines;
-        else if (prevContent.length > 0 && lines.length > 0 && editor.attractAttention) {
-            if (clearPromise) {
-                $timeout.cancel(clearPromise);
-
-                _clearSelection(editor);
-            }
-
-            const selections = [];
-
-            let newIx = 0;
-            let prevIx = 0;
-
-            let prevLen = prevContent.length - (prevContent[prevContent.length - 1] === '' ? 1 : 0);
-            let newLen = lines.length - (lines[lines.length - 1] === '' ? 1 : 0);
-
-            const removed = newLen < prevLen;
-
-            let skipEnd = 0;
-
-            let selected = false;
-            let scrollTo = -1;
-
-            while (lines[newLen - 1] === prevContent[prevLen - 1] && newLen > 0 && prevLen > 0) {
-                prevLen -= 1;
-                newLen -= 1;
-
-                skipEnd += 1;
-            }
-
-            while (newIx < newLen || prevIx < prevLen) {
-                let start = -1;
-                let stop = -1;
-
-                // Find an index of a first line with different text.
-                for (; (newIx < newLen || prevIx < prevLen) && start < 0; newIx++, prevIx++) {
-                    if (newIx >= newLen || prevIx >= prevLen || lines[newIx] !== prevContent[prevIx]) {
-                        start = newIx;
-
-                        break;
-                    }
-                }
-
-                if (start >= 0) {
-                    // Find an index of a last line with different text by checking last string of old and new content in reverse order.
-                    for (let i = start; i < newLen && stop < 0; i++) {
-                        for (let j = prevIx; j < prevLen && stop < 0; j++) {
-                            if (lines[i] === prevContent[j] && lines[i] !== '') {
-                                stop = i;
-
-                                newIx = i;
-                                prevIx = j;
-
-                                break;
-                            }
-                        }
-                    }
-
-                    if (stop < 0) {
-                        stop = newLen;
-
-                        newIx = newLen;
-                        prevIx = prevLen;
-                    }
-
-                    if (start === stop) {
-                        if (removed)
-                            start = Math.max(0, start - 1);
-
-                        stop = Math.min(newLen + skipEnd, stop + 1);
-                    }
-
-                    if (start <= stop) {
-                        selections.push({start, stop});
-
-                        if (!selected)
-                            scrollTo = start;
-
-                        selected = true;
-                    }
-                }
-            }
-
-            // Run clear selection one time.
-            if (selected) {
-                _fadeIn(editor, selections);
-
-                editor.clearPromise = $timeout(() => {
-                    _fadeOut(editor, selections);
-
-                    editor.clearPromise = null;
-                }, 2000);
-
-                editor.scrollToRow(scrollTo);
-            }
-
-            prevContent = [];
-        }
-        else
-            editor.attractAttention = true;
-    };
-
-
-    const link = (scope, $element, $attrs, [igniteUiAceTabs1, igniteUiAceTabs2]) => {
-        const igniteUiAceTabs = igniteUiAceTabs1 || igniteUiAceTabs2;
-
-        if (!igniteUiAceTabs)
-            return;
-
-        igniteUiAceTabs.onLoad = (editor) => {
-            editor.setReadOnly(true);
-            editor.setOption('highlightActiveLine', false);
-            editor.setAutoScrollEditorIntoView(true);
-            editor.$blockScrolling = Infinity;
-            editor.attractAttention = false;
-
-            const renderer = editor.renderer;
-
-            renderer.setHighlightGutterLine(false);
-            renderer.setShowPrintMargin(false);
-            renderer.setOption('fontSize', '10px');
-            renderer.setOption('maxLines', '50');
-
-            editor.setTheme('ace/theme/chrome');
-        };
-
-        igniteUiAceTabs.onChange = onChange;
-    };
-
-    return {
-        restrict: 'C',
-        link,
-        require: ['?igniteUiAceTabs', '?^igniteUiAceTabs']
-    };
-}]];

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/src/main/js/app/modules/states/configuration/summary/summary-tabs.directive.js
----------------------------------------------------------------------
diff --git a/modules/web-console/src/main/js/app/modules/states/configuration/summary/summary-tabs.directive.js b/modules/web-console/src/main/js/app/modules/states/configuration/summary/summary-tabs.directive.js
deleted file mode 100644
index f8094af..0000000
--- a/modules/web-console/src/main/js/app/modules/states/configuration/summary/summary-tabs.directive.js
+++ /dev/null
@@ -1,50 +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 ['summaryTabs', [() => {
-    const link = (scope, $element, $attrs, [igniteUiAceTabs1, igniteUiAceTabs2]) => {
-        const igniteUiAceTabs = igniteUiAceTabs1 || igniteUiAceTabs2;
-
-        if (!igniteUiAceTabs)
-            return;
-
-        igniteUiAceTabs.onLoad = (editor) => {
-            editor.setReadOnly(true);
-            editor.setOption('highlightActiveLine', false);
-            editor.setAutoScrollEditorIntoView(true);
-            editor.$blockScrolling = Infinity;
-
-            const renderer = editor.renderer;
-
-            renderer.setHighlightGutterLine(false);
-            renderer.setShowPrintMargin(false);
-            renderer.setOption('fontFamily', 'monospace');
-            renderer.setOption('fontSize', '12px');
-            renderer.setOption('minLines', '25');
-            renderer.setOption('maxLines', '25');
-
-            editor.setTheme('ace/theme/chrome');
-        };
-    };
-
-    return {
-        priority: 1000,
-        restrict: 'C',
-        link,
-        require: ['?igniteUiAceTabs', '?^igniteUiAceTabs']
-    };
-}]];

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/src/main/js/app/modules/states/configuration/summary/summary.controller.js
----------------------------------------------------------------------
diff --git a/modules/web-console/src/main/js/app/modules/states/configuration/summary/summary.controller.js b/modules/web-console/src/main/js/app/modules/states/configuration/summary/summary.controller.js
deleted file mode 100644
index 1b19e3a..0000000
--- a/modules/web-console/src/main/js/app/modules/states/configuration/summary/summary.controller.js
+++ /dev/null
@@ -1,359 +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 _ from 'lodash';
-import JSZip from 'jszip';
-import saver from 'file-saver';
-
-export default [
-    '$rootScope', '$scope', '$http', 'IgniteLegacyUtils', 'IgniteLoading', '$filter', 'ConfigurationSummaryResource', 'JavaTypes', 'IgniteVersion', 'GeneratorDocker', 'GeneratorPom',
-    function($root, $scope, $http, LegacyUtils, Loading, $filter, Resource, JavaTypes, IgniteVersion, docker, pom) {
-        const ctrl = this;
-
-        $scope.ui = { ready: false };
-
-        Loading.start('summaryPage');
-
-        Resource.read().then(({clusters}) => {
-            $scope.clusters = clusters;
-            $scope.clustersMap = {};
-            $scope.clustersView = _.map(clusters, (item) => {
-                const { _id, name } = item;
-
-                $scope.clustersMap[_id] = item;
-
-                return { _id, name };
-            });
-
-            Loading.finish('summaryPage');
-
-            $scope.ui.ready = true;
-
-            if (!_.isEmpty(clusters)) {
-                const idx = sessionStorage.summarySelectedId || 0;
-
-                $scope.selectItem(clusters[idx]);
-            }
-        });
-
-        $scope.contentVisible = (rows, row) => {
-            return !row || !row._id || _.findIndex(rows, (item) => item._id === row._id) >= 0;
-        };
-
-        $scope.widthIsSufficient = LegacyUtils.widthIsSufficient;
-        $scope.dialects = {};
-
-        $scope.projectStructureOptions = {
-            nodeChildren: 'children',
-            dirSelectable: false,
-            injectClasses: {
-                iExpanded: 'fa fa-folder-open-o',
-                iCollapsed: 'fa fa-folder-o'
-            },
-            equality: (node1, node2) => {
-                return node1 === node2;
-            }
-        };
-
-        const javaConfigFolder = {
-            type: 'folder',
-            name: 'config',
-            children: [
-                { type: 'file', name: 'ClientConfigurationFactory.java' },
-                { type: 'file', name: 'ServerConfigurationFactory.java' }
-            ]
-        };
-
-        const javaStartupFolder = {
-            type: 'folder',
-            name: 'startup',
-            children: [
-                { type: 'file', name: 'ClientNodeCodeStartup.java' },
-                { type: 'file', name: 'ClientNodeSpringStartup.java' },
-                { type: 'file', name: 'ServerNodeCodeStartup.java' },
-                { type: 'file', name: 'ServerNodeSpringStartup.java' }
-            ]
-        };
-
-        const demoFolder = {
-            type: 'folder',
-            name: 'demo',
-            children: [
-                { type: 'file', name: 'DemoStartup.java' }
-            ]
-        };
-
-        const resourcesFolder = {
-            type: 'folder',
-            name: 'resources',
-            children: [
-                { type: 'file', name: 'secret.properties' }
-            ]
-        };
-
-        const javaFolder = {
-            type: 'folder',
-            name: 'java',
-            children: [
-                {
-                    type: 'folder',
-                    name: 'config',
-                    children: [
-                        javaConfigFolder,
-                        javaStartupFolder
-                    ]
-                }
-            ]
-        };
-
-        const clnCfg = { type: 'file', name: 'client.xml' };
-
-        const srvCfg = { type: 'file', name: 'server.xml' };
-
-        const mainFolder = {
-            type: 'folder',
-            name: 'main',
-            children: [javaFolder]
-        };
-
-        const projectStructureRoot = {
-            type: 'folder',
-            name: 'project.zip',
-            children: [
-                {
-                    type: 'folder',
-                    name: 'config',
-                    children: [clnCfg, srvCfg]
-                },
-                {
-                    type: 'folder',
-                    name: 'jdbc-drivers',
-                    children: [
-                        { type: 'file', name: 'README.txt' }
-                    ]
-                },
-                {
-                    type: 'folder',
-                    name: 'src',
-                    children: [mainFolder]
-                },
-                { type: 'file', name: '.dockerignore' },
-                { type: 'file', name: 'Dockerfile' },
-                { type: 'file', name: 'pom.xml' },
-                { type: 'file', name: 'README.txt' }
-            ]
-        };
-
-        $scope.projectStructure = [projectStructureRoot];
-
-        $scope.projectStructureExpanded = [projectStructureRoot];
-
-        $scope.tabsServer = { activeTab: 0 };
-        $scope.tabsClient = { activeTab: 0 };
-
-        /**
-         *
-         * @param {Object} node - Tree node.
-         * @param {string[]} path - Path to find.
-         * @returns {Object} Tree node.
-         */
-        function getOrCreateFolder(node, path) {
-            if (_.isEmpty(path))
-                return node;
-
-            const leaf = path.shift();
-
-            let children = null;
-
-            if (!_.isEmpty(node.children)) {
-                children = _.find(node.children, {type: 'folder', name: leaf});
-
-                if (children)
-                    return getOrCreateFolder(children, path);
-            }
-
-            children = {type: 'folder', name: leaf, children: []};
-
-            node.children.push(children);
-
-            node.children = _.orderBy(node.children, ['type', 'name'], ['desc', 'asc']);
-
-            return getOrCreateFolder(children, path);
-        }
-
-        function addClass(fullClsName) {
-            const path = fullClsName.split('.');
-            const leaf = {type: 'file', name: path.pop() + '.java'};
-            const folder = getOrCreateFolder(javaFolder, path);
-
-            if (!_.find(folder.children, leaf))
-                folder.children.push(leaf);
-        }
-
-        $scope.selectItem = (cluster) => {
-            delete ctrl.cluster;
-
-            if (!cluster)
-                return;
-
-            cluster = $scope.clustersMap[cluster._id];
-
-            ctrl.cluster = cluster;
-
-            $scope.cluster = cluster;
-            $scope.selectedItem = cluster;
-            $scope.dialects = {};
-
-            sessionStorage.summarySelectedId = $scope.clusters.indexOf(cluster);
-
-            mainFolder.children = [javaFolder];
-            javaFolder.children = [javaConfigFolder, javaStartupFolder];
-
-            if ($generatorCommon.secretPropertiesNeeded(cluster))
-                mainFolder.children.push(resourcesFolder);
-
-            if ($generatorJava.isDemoConfigured(cluster, $root.IgniteDemoMode))
-                javaFolder.children.push(demoFolder);
-
-            _.forEach(cluster.caches, (cache) => {
-                if (cache.cacheStoreFactory) {
-                    const store = cache.cacheStoreFactory[cache.cacheStoreFactory.kind];
-
-                    if (store && store.dialect)
-                        $scope.dialects[store.dialect] = true;
-                }
-
-                _.forEach(cache.domains, (domain) => {
-                    if (!_.isEmpty(domain.keyFields)) {
-                        if (JavaTypes.nonBuiltInClass(domain.keyType))
-                            addClass(domain.keyType);
-
-                        addClass(domain.valueType);
-                    }
-                });
-            });
-
-            projectStructureRoot.name = cluster.name + '-project.zip';
-            clnCfg.name = cluster.name + '-client.xml';
-            srvCfg.name = cluster.name + '-server.xml';
-        };
-
-        $scope.$watch('cluster', (cluster) => {
-            if (!cluster)
-                return;
-
-            if (!$filter('hasPojo')(cluster) && $scope.tabsClient.activeTab === 3)
-                $scope.tabsClient.activeTab = 0;
-        });
-
-        $scope.$watch('cluster._id', () => {
-            $scope.tabsClient.init = [];
-            $scope.tabsServer.init = [];
-        });
-
-        // TODO IGNITE-2114: implemented as independent logic for download.
-        $scope.downloadConfiguration = function() {
-            const cluster = $scope.cluster;
-            const clientNearCfg = cluster.clientNearCfg;
-
-            const zip = new JSZip();
-
-            if (!ctrl.data)
-                ctrl.data = {};
-
-            if (!ctrl.data.docker)
-                ctrl.data.docker = docker.generate(cluster, 'latest');
-
-            zip.file('Dockerfile', ctrl.data.docker);
-            zip.file('.dockerignore', docker.ignoreFile());
-
-            const builder = $generatorProperties.generateProperties(cluster);
-
-            if (builder)
-                zip.file('src/main/resources/secret.properties', builder.asString());
-
-            const srcPath = 'src/main/java/';
-
-            const serverXml = 'config/' + cluster.name + '-server.xml';
-            const clientXml = 'config/' + cluster.name + '-client.xml';
-
-            zip.file(serverXml, $generatorXml.cluster(cluster));
-            zip.file(clientXml, $generatorXml.cluster(cluster, clientNearCfg));
-
-            zip.file(srcPath + 'config/ServerConfigurationFactory.java', $generatorJava.cluster(cluster, 'config', 'ServerConfigurationFactory', null));
-            zip.file(srcPath + 'config/ClientConfigurationFactory.java', $generatorJava.cluster(cluster, 'config', 'ClientConfigurationFactory', clientNearCfg));
-
-            if ($generatorJava.isDemoConfigured(cluster, $root.IgniteDemoMode)) {
-                zip.file(srcPath + 'demo/DemoStartup.java', $generatorJava.nodeStartup(cluster, 'demo', 'DemoStartup',
-                    'ServerConfigurationFactory.createConfiguration()', 'config.ServerConfigurationFactory'));
-            }
-
-            zip.file(srcPath + 'startup/ServerNodeSpringStartup.java', $generatorJava.nodeStartup(cluster, 'startup', 'ServerNodeSpringStartup', '"' + serverXml + '"'));
-            zip.file(srcPath + 'startup/ClientNodeSpringStartup.java', $generatorJava.nodeStartup(cluster, 'startup', 'ClientNodeSpringStartup', '"' + clientXml + '"'));
-
-            zip.file(srcPath + 'startup/ServerNodeCodeStartup.java', $generatorJava.nodeStartup(cluster, 'startup', 'ServerNodeCodeStartup',
-                'ServerConfigurationFactory.createConfiguration()', 'config.ServerConfigurationFactory'));
-            zip.file(srcPath + 'startup/ClientNodeCodeStartup.java', $generatorJava.nodeStartup(cluster, 'startup', 'ClientNodeCodeStartup',
-                'ClientConfigurationFactory.createConfiguration()', 'config.ClientConfigurationFactory', clientNearCfg));
-
-            zip.file('pom.xml', pom.generate(cluster, IgniteVersion.version).asString());
-
-            zip.file('README.txt', $generatorReadme.readme().asString());
-            zip.file('jdbc-drivers/README.txt', $generatorReadme.readmeJdbc().asString());
-
-            if (!ctrl.data.pojos)
-                ctrl.data.pojos = $generatorJava.pojos(cluster.caches);
-
-            for (const pojo of ctrl.data.pojos) {
-                if (pojo.keyClass && JavaTypes.nonBuiltInClass(pojo.keyType))
-                    zip.file(srcPath + pojo.keyType.replace(/\./g, '/') + '.java', pojo.keyClass);
-
-                zip.file(srcPath + pojo.valueType.replace(/\./g, '/') + '.java', pojo.valueClass);
-            }
-
-            $generatorOptional.optionalContent(zip, cluster);
-
-            zip.generateAsync({type: 'blob', compression: 'DEFLATE', mimeType: 'application/octet-stream'})
-                .then((blob) => saver.saveAs(blob, cluster.name + '-project.zip'));
-        };
-
-        /**
-         * @returns {boolean} 'true' if at least one proprietary JDBC driver is configured for cache store.
-         */
-        $scope.downloadJdbcDriversVisible = function() {
-            const dialects = $scope.dialects;
-
-            return !!(dialects.Oracle || dialects.DB2 || dialects.SQLServer);
-        };
-
-        /**
-         * Open download proprietary JDBC driver pages.
-         */
-        $scope.downloadJdbcDrivers = function() {
-            const dialects = $scope.dialects;
-
-            if (dialects.Oracle)
-                window.open('http://www.oracle.com/technetwork/apps-tech/jdbc-112010-090769.html');
-
-            if (dialects.DB2)
-                window.open('http://www-01.ibm.com/support/docview.wss?uid=swg21363866');
-
-            if (dialects.SQLServer)
-                window.open('https://www.microsoft.com/en-us/download/details.aspx?id=11774');
-        };
-    }
-];


[49/52] ignite git commit: Web Console beta-3. Updated Ignite version.

Posted by ak...@apache.org.
Web Console beta-3. Updated Ignite version.


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

Branch: refs/heads/master
Commit: 4e1a8ffe27fc7ce5293c756df28d7ca5b3f90167
Parents: 492ab12
Author: Andrey Novikov <an...@apache.org>
Authored: Thu Sep 8 15:30:55 2016 +0700
Committer: Andrey Novikov <an...@apache.org>
Committed: Thu Sep 8 15:30:55 2016 +0700

----------------------------------------------------------------------
 .../web-console/frontend/app/modules/version/Version.provider.js   | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/ignite/blob/4e1a8ffe/modules/web-console/frontend/app/modules/version/Version.provider.js
----------------------------------------------------------------------
diff --git a/modules/web-console/frontend/app/modules/version/Version.provider.js b/modules/web-console/frontend/app/modules/version/Version.provider.js
index fe503ab..31ff8d0 100644
--- a/modules/web-console/frontend/app/modules/version/Version.provider.js
+++ b/modules/web-console/frontend/app/modules/version/Version.provider.js
@@ -21,7 +21,7 @@ angular
     .module('ignite-console.version', [])
     .provider('IgniteVersion', function() {
         const version = {
-            version: '1.6.0'
+            version: '1.7.0'
         };
 
         this.update = (newVersion) => {


[12/52] ignite git commit: Web Console beta-3.

Posted by ak...@apache.org.
http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/src/main/js/app/services/ModelNormalizer.service.js
----------------------------------------------------------------------
diff --git a/modules/web-console/src/main/js/app/services/ModelNormalizer.service.js b/modules/web-console/src/main/js/app/services/ModelNormalizer.service.js
deleted file mode 100644
index 4c7052b..0000000
--- a/modules/web-console/src/main/js/app/services/ModelNormalizer.service.js
+++ /dev/null
@@ -1,59 +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.
- */
-
-// Service to normalize objects for dirty checks.
-export default ['IgniteModelNormalizer', () => {
-    /**
-     * Normalize object for dirty checks.
-     *
-     * @param original
-     * @param dest
-     * @returns {*}
-     */
-    const normalize = (original, dest) => {
-        if (_.isUndefined(original))
-            return dest;
-
-        if (_.isObject(original)) {
-            _.forOwn(original, (value, key) => {
-                if (/\$\$hashKey/.test(key))
-                    return;
-
-                const attr = normalize(value);
-
-                if (!_.isNil(attr)) {
-                    dest = dest || {};
-                    dest[key] = attr;
-                }
-            });
-        } else if (_.isBoolean(original) && original === true)
-            dest = original;
-        else if ((_.isString(original) && original.length) || _.isNumber(original))
-            dest = original;
-        else if (_.isArray(original) && original.length)
-            dest = _.map(original, (value) => normalize(value, {}));
-
-        return dest;
-    };
-
-    return {
-        normalize,
-        isEqual(prev, cur) {
-            return _.isEqual(prev, normalize(cur));
-        }
-    };
-}];

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/src/main/js/app/services/UnsavedChangesGuard.service.js
----------------------------------------------------------------------
diff --git a/modules/web-console/src/main/js/app/services/UnsavedChangesGuard.service.js b/modules/web-console/src/main/js/app/services/UnsavedChangesGuard.service.js
deleted file mode 100644
index 91244b0..0000000
--- a/modules/web-console/src/main/js/app/services/UnsavedChangesGuard.service.js
+++ /dev/null
@@ -1,38 +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.
- */
-
-const MSG = 'You have unsaved changes.\n\nAre you sure you want to discard them?';
-
-// Service that show confirmation about unsaved changes on user change location.
-export default ['IgniteUnsavedChangesGuard', ['$rootScope', ($root) => {
-    return {
-        install(scope, customDirtyCheck = () => scope.ui.inputForm.$dirty) {
-            scope.$on('$destroy', () => window.onbeforeunload = null);
-
-            const unbind = $root.$on('$stateChangeStart', (event) => {
-                if (_.get(scope, 'ui.inputForm', false) && customDirtyCheck()) {
-                    if (!confirm(MSG)) // eslint-disable-line no-alert
-                        event.preventDefault();
-                    else
-                        unbind();
-                }
-            });
-
-            window.onbeforeunload = () => _.get(scope, 'ui.inputForm.$dirty', false) ? MSG : null;
-        }
-    };
-}]];

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/src/main/js/app/vendor.js
----------------------------------------------------------------------
diff --git a/modules/web-console/src/main/js/app/vendor.js b/modules/web-console/src/main/js/app/vendor.js
deleted file mode 100644
index a8eeea7..0000000
--- a/modules/web-console/src/main/js/app/vendor.js
+++ /dev/null
@@ -1,54 +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 'jquery';
-import 'angular';
-import 'angular-animate';
-import 'angular-sanitize';
-import 'angular-strap';
-import 'angular-strap/dist/angular-strap.tpl';
-import 'angular-socket-io';
-import 'angular-retina';
-import 'angular-ui-router';
-import 'ui-router-metatags/dist/ui-router-metatags';
-import 'angular-smart-table';
-import 'angular-ui-grid/ui-grid';
-import 'angular-drag-and-drop-lists';
-import 'angular-nvd3';
-import 'angular-tree-control';
-import 'angular-gridster';
-import 'bootstrap-sass/assets/javascripts/bootstrap/transition';
-import 'bootstrap-sass/assets/javascripts/bootstrap/carousel';
-import 'brace';
-import 'brace/mode/xml';
-import 'brace/mode/sql';
-import 'brace/mode/java';
-import 'brace/mode/dockerfile';
-import 'brace/mode/snippets';
-import 'brace/theme/chrome';
-import 'brace/ext/language_tools';
-import 'brace/ext/searchbox';
-import 'file-saver';
-import 'jszip';
-import 'nvd3';
-import 'query-command-supported';
-import 'angular-gridster/dist/angular-gridster.min.css';
-import 'angular-tree-control/css/tree-control-attribute.css';
-import 'angular-tree-control/css/tree-control.css';
-import 'angular-ui-grid/ui-grid.css';
-import 'angular-motion/dist/angular-motion.css';
-import 'nvd3/build/nv.d3.css';

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/src/main/js/controllers/admin-controller.js
----------------------------------------------------------------------
diff --git a/modules/web-console/src/main/js/controllers/admin-controller.js b/modules/web-console/src/main/js/controllers/admin-controller.js
deleted file mode 100644
index 9e5aea7..0000000
--- a/modules/web-console/src/main/js/controllers/admin-controller.js
+++ /dev/null
@@ -1,91 +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.
- */
-
-// Controller for Admin screen.
-export default ['adminController', [
-    '$rootScope', '$scope', '$http', '$q', '$state', 'IgniteMessages', 'IgniteConfirm', 'User', 'IgniteCountries',
-    ($rootScope, $scope, $http, $q, $state, Messages, Confirm, User, Countries) => {
-        $scope.users = null;
-
-        const _reloadUsers = () => {
-            $http.post('/api/v1/admin/list')
-                .then(({data}) => {
-                    $scope.users = data;
-
-                    _.forEach($scope.users, (user) => {
-                        user.userName = user.firstName + ' ' + user.lastName;
-                        user.countryCode = Countries.getByName(user.country).code;
-                        user.label = user.userName + ' ' + user.email + ' ' +
-                            (user.company || '') + ' ' + (user.countryCode || '');
-                    });
-                })
-                .catch(Messages.showError);
-        };
-
-        _reloadUsers();
-
-        $scope.becomeUser = function(user) {
-            $http.get('/api/v1/admin/become', { params: {viewedUserId: user._id}})
-                .then(User.read)
-                .then((becomeUser) => {
-                    $rootScope.$broadcast('user', becomeUser);
-
-                    $state.go('base.configuration.clusters');
-                })
-                .catch(Messages.showError);
-        };
-
-        $scope.removeUser = (user) => {
-            Confirm.confirm('Are you sure you want to remove user: "' + user.userName + '"?')
-                .then(() => {
-                    $http.post('/api/v1/admin/remove', {userId: user._id})
-                        .success(() => {
-                            const i = _.findIndex($scope.users, (u) => u._id === user._id);
-
-                            if (i >= 0)
-                                $scope.users.splice(i, 1);
-
-                            Messages.showInfo('User has been removed: "' + user.userName + '"');
-                        })
-                        .error((err, status) => {
-                            if (status === 503)
-                                Messages.showInfo(err);
-                            else
-                                Messages.showError(Messages.errorMessage('Failed to remove user: ', err));
-                        });
-                });
-        };
-
-        $scope.toggleAdmin = (user) => {
-            if (user.adminChanging)
-                return;
-
-            user.adminChanging = true;
-
-            $http.post('/api/v1/admin/save', {userId: user._id, adminFlag: !user.admin})
-                .success(() => {
-                    user.admin = !user.admin;
-
-                    Messages.showInfo('Admin right was successfully toggled for user: "' + user.userName + '"');
-                })
-                .error((err) => {
-                    Messages.showError(Messages.errorMessage('Failed to toggle admin right for user: ', err));
-                })
-                .finally(() => user.adminChanging = false);
-        };
-    }
-]];

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/src/main/js/controllers/caches-controller.js
----------------------------------------------------------------------
diff --git a/modules/web-console/src/main/js/controllers/caches-controller.js b/modules/web-console/src/main/js/controllers/caches-controller.js
deleted file mode 100644
index cbd681e..0000000
--- a/modules/web-console/src/main/js/controllers/caches-controller.js
+++ /dev/null
@@ -1,470 +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.
- */
-
-// Controller for Caches screen.
-export default ['cachesController', [
-    '$scope', '$http', '$state', '$filter', '$timeout', 'IgniteLegacyUtils', 'IgniteMessages', 'IgniteConfirm', 'IgniteClone', 'IgniteLoading', 'IgniteModelNormalizer', 'IgniteUnsavedChangesGuard',
-    function($scope, $http, $state, $filter, $timeout, LegacyUtils, Messages, Confirm, Clone, Loading, ModelNormalizer, UnsavedChangesGuard) {
-        UnsavedChangesGuard.install($scope);
-
-        const emptyCache = {empty: true};
-
-        let __original_value;
-
-        const blank = {
-            evictionPolicy: {},
-            cacheStoreFactory: {},
-            nearConfiguration: {}
-        };
-
-        // We need to initialize backupItem with empty object in order to properly used from angular directives.
-        $scope.backupItem = emptyCache;
-
-        $scope.ui = LegacyUtils.formUI();
-        $scope.ui.activePanels = [0];
-        $scope.ui.topPanels = [0, 1, 2, 3];
-
-        $scope.hidePopover = LegacyUtils.hidePopover;
-        $scope.saveBtnTipText = LegacyUtils.saveBtnTipText;
-        $scope.widthIsSufficient = LegacyUtils.widthIsSufficient;
-
-        const showPopoverMessage = LegacyUtils.showPopoverMessage;
-
-        $scope.contentVisible = function() {
-            const item = $scope.backupItem;
-
-            return !item.empty && (!item._id || _.find($scope.displayedRows, {_id: item._id}));
-        };
-
-        $scope.toggleExpanded = function() {
-            $scope.ui.expanded = !$scope.ui.expanded;
-
-            LegacyUtils.hidePopover();
-        };
-
-        $scope.caches = [];
-        $scope.domains = [];
-
-        function _cacheLbl(cache) {
-            return cache.name + ', ' + cache.cacheMode + ', ' + cache.atomicityMode;
-        }
-
-        function selectFirstItem() {
-            if ($scope.caches.length > 0)
-                $scope.selectItem($scope.caches[0]);
-        }
-
-        function cacheDomains(item) {
-            return _.reduce($scope.domains, function(memo, domain) {
-                if (item && _.includes(item.domains, domain.value))
-                    memo.push(domain.meta);
-
-                return memo;
-            }, []);
-        }
-
-        Loading.start('loadingCachesScreen');
-
-        // When landing on the page, get caches and show them.
-        $http.post('/api/v1/configuration/caches/list')
-            .success(function(data) {
-                const validFilter = $filter('domainsValidation');
-
-                $scope.spaces = data.spaces;
-                $scope.caches = data.caches;
-
-                _.forEach($scope.caches, (cache) => cache.label = _cacheLbl(cache));
-
-                $scope.clusters = _.map(data.clusters, function(cluster) {
-                    return {
-                        value: cluster._id,
-                        label: cluster.name,
-                        caches: cluster.caches
-                    };
-                });
-
-                $scope.domains = _.sortBy(_.map(validFilter(data.domains, true, false), function(domain) {
-                    return {
-                        value: domain._id,
-                        label: domain.valueType,
-                        kind: domain.kind,
-                        meta: domain
-                    };
-                }), 'label');
-
-                if ($state.params.linkId)
-                    $scope.createItem($state.params.linkId);
-                else {
-                    const lastSelectedCache = angular.fromJson(sessionStorage.lastSelectedCache);
-
-                    if (lastSelectedCache) {
-                        const idx = _.findIndex($scope.caches, function(cache) {
-                            return cache._id === lastSelectedCache;
-                        });
-
-                        if (idx >= 0)
-                            $scope.selectItem($scope.caches[idx]);
-                        else {
-                            sessionStorage.removeItem('lastSelectedCache');
-
-                            selectFirstItem();
-                        }
-                    }
-                    else
-                        selectFirstItem();
-                }
-
-                $scope.$watch('ui.inputForm.$valid', function(valid) {
-                    if (valid && ModelNormalizer.isEqual(__original_value, $scope.backupItem))
-                        $scope.ui.inputForm.$dirty = false;
-                });
-
-                $scope.$watch('backupItem', function(val) {
-                    const form = $scope.ui.inputForm;
-
-                    if (form.$pristine || (form.$valid && ModelNormalizer.isEqual(__original_value, val)))
-                        form.$setPristine();
-                    else
-                        form.$setDirty();
-                }, true);
-            })
-            .catch(Messages.showError)
-            .finally(function() {
-                $scope.ui.ready = true;
-                $scope.ui.inputForm.$setPristine();
-                Loading.finish('loadingCachesScreen');
-            });
-
-        $scope.selectItem = function(item, backup) {
-            function selectItem() {
-                $scope.selectedItem = item;
-
-                if (item && !_.get(item.cacheStoreFactory.CacheJdbcBlobStoreFactory, 'connectVia'))
-                    _.set(item.cacheStoreFactory, 'CacheJdbcBlobStoreFactory.connectVia', 'DataSource');
-
-                try {
-                    if (item && item._id)
-                        sessionStorage.lastSelectedCache = angular.toJson(item._id);
-                    else
-                        sessionStorage.removeItem('lastSelectedCache');
-                }
-                catch (ignored) {
-                    // No-op.
-                }
-
-                if (backup)
-                    $scope.backupItem = backup;
-                else if (item)
-                    $scope.backupItem = angular.copy(item);
-                else
-                    $scope.backupItem = emptyCache;
-
-                $scope.backupItem = angular.merge({}, blank, $scope.backupItem);
-
-                __original_value = ModelNormalizer.normalize($scope.backupItem);
-
-                if (LegacyUtils.getQueryVariable('new'))
-                    $state.go('base.configuration.caches');
-            }
-
-            LegacyUtils.confirmUnsavedChanges($scope.backupItem && $scope.ui.inputForm.$dirty, selectItem);
-        };
-
-        $scope.linkId = () => $scope.backupItem._id ? $scope.backupItem._id : 'create';
-
-        function prepareNewItem(linkId) {
-            return {
-                space: $scope.spaces[0]._id,
-                cacheMode: 'PARTITIONED',
-                atomicityMode: 'ATOMIC',
-                readFromBackup: true,
-                copyOnRead: true,
-                clusters: linkId && _.find($scope.clusters, {value: linkId})
-                    ? [linkId] : _.map($scope.clusters, function(cluster) { return cluster.value; }),
-                domains: linkId && _.find($scope.domains, { value: linkId }) ? [linkId] : [],
-                cacheStoreFactory: {CacheJdbcBlobStoreFactory: {connectVia: 'DataSource'}}
-            };
-        }
-
-        // Add new cache.
-        $scope.createItem = function(linkId) {
-            $timeout(() => LegacyUtils.ensureActivePanel($scope.ui, 'general', 'cacheName'));
-
-            $scope.selectItem(null, prepareNewItem(linkId));
-        };
-
-        function cacheClusters() {
-            return _.filter($scope.clusters, (cluster) => _.includes($scope.backupItem.clusters, cluster.value));
-        }
-
-        function clusterCaches(cluster) {
-            const caches = _.filter($scope.caches,
-                (cache) => cache._id !== $scope.backupItem._id && _.includes(cluster.caches, cache._id));
-
-            caches.push($scope.backupItem);
-
-            return caches;
-        }
-
-        function checkDataSources() {
-            const clusters = cacheClusters();
-
-            let checkRes = {checked: true};
-
-            const failCluster = _.find(clusters, (cluster) => {
-                const caches = clusterCaches(cluster);
-
-                checkRes = LegacyUtils.checkCachesDataSources(caches, $scope.backupItem);
-
-                return !checkRes.checked;
-            });
-
-            if (!checkRes.checked) {
-                return showPopoverMessage($scope.ui, 'store', checkRes.firstCache.cacheStoreFactory.kind === 'CacheJdbcPojoStoreFactory' ? 'pojoDialect' : 'blobDialect',
-                    'Found cache "' + checkRes.secondCache.name + '" in cluster "' + failCluster.label + '" ' +
-                    'with the same data source bean name "' + checkRes.firstCache.cacheStoreFactory[checkRes.firstCache.cacheStoreFactory.kind].dataSourceBean +
-                    '" and different database: "' + LegacyUtils.cacheStoreJdbcDialectsLabel(checkRes.firstDB) + '" in current cache and "' +
-                    LegacyUtils.cacheStoreJdbcDialectsLabel(checkRes.secondDB) + '" in "' + checkRes.secondCache.name + '"', 10000);
-            }
-
-            return true;
-        }
-
-        function checkSQLSchemas() {
-            const clusters = cacheClusters();
-
-            let checkRes = {checked: true};
-
-            const failCluster = _.find(clusters, (cluster) => {
-                const caches = clusterCaches(cluster);
-
-                checkRes = LegacyUtils.checkCacheSQLSchemas(caches, $scope.backupItem);
-
-                return !checkRes.checked;
-            });
-
-            if (!checkRes.checked) {
-                return showPopoverMessage($scope.ui, 'query', 'sqlSchema',
-                    'Found cache "' + checkRes.secondCache.name + '" in cluster "' + failCluster.label + '" ' +
-                    'with the same SQL schema name "' + checkRes.firstCache.sqlSchema + '"', 10000);
-            }
-
-            return true;
-        }
-
-        function checkStoreFactoryBean(storeFactory, beanFieldId) {
-            if (!LegacyUtils.isValidJavaIdentifier('Data source bean', storeFactory.dataSourceBean, beanFieldId, $scope.ui, 'store'))
-                return false;
-
-            return checkDataSources();
-        }
-
-        function checkStoreFactory(item) {
-            const cacheStoreFactorySelected = item.cacheStoreFactory && item.cacheStoreFactory.kind;
-
-            if (cacheStoreFactorySelected) {
-                const storeFactory = item.cacheStoreFactory[item.cacheStoreFactory.kind];
-
-                if (item.cacheStoreFactory.kind === 'CacheJdbcPojoStoreFactory' && !checkStoreFactoryBean(storeFactory, 'pojoDataSourceBean'))
-                    return false;
-
-                if (item.cacheStoreFactory.kind === 'CacheJdbcBlobStoreFactory' && storeFactory.connectVia !== 'URL'
-                    && !checkStoreFactoryBean(storeFactory, 'blobDataSourceBean'))
-                    return false;
-            }
-
-            if ((item.readThrough || item.writeThrough) && !cacheStoreFactorySelected)
-                return showPopoverMessage($scope.ui, 'store', 'cacheStoreFactory', (item.readThrough ? 'Read' : 'Write') + ' through are enabled but store is not configured!');
-
-            if (item.writeBehindEnabled && !cacheStoreFactorySelected)
-                return showPopoverMessage($scope.ui, 'store', 'cacheStoreFactory', 'Write behind enabled but store is not configured!');
-
-            if (cacheStoreFactorySelected && !item.readThrough && !item.writeThrough)
-                return showPopoverMessage($scope.ui, 'store', 'readThroughTooltip', 'Store is configured but read/write through are not enabled!');
-
-            return true;
-        }
-
-        // Check cache logical consistency.
-        function validate(item) {
-            LegacyUtils.hidePopover();
-
-            if (LegacyUtils.isEmptyString(item.name))
-                return showPopoverMessage($scope.ui, 'general', 'cacheName', 'Cache name should not be empty!');
-
-            if (item.memoryMode === 'ONHEAP_TIERED' && item.offHeapMaxMemory > 0 && !LegacyUtils.isDefined(item.evictionPolicy.kind))
-                return showPopoverMessage($scope.ui, 'memory', 'evictionPolicyKind', 'Eviction policy should not be configured!');
-
-            if (!LegacyUtils.checkFieldValidators($scope.ui))
-                return false;
-
-            if (item.memoryMode === 'OFFHEAP_VALUES' && !_.isEmpty(item.domains))
-                return showPopoverMessage($scope.ui, 'memory', 'memoryMode', 'Query indexing could not be enabled while values are stored off-heap!');
-
-            if (item.memoryMode === 'OFFHEAP_TIERED' && (!LegacyUtils.isDefined(item.offHeapMaxMemory) || item.offHeapMaxMemory < 0))
-                return showPopoverMessage($scope.ui, 'memory', 'offHeapMaxMemory', 'Off-heap max memory should be specified!');
-
-            if (!checkSQLSchemas())
-                return false;
-
-            if (!checkStoreFactory(item))
-                return false;
-
-            if (item.writeBehindFlushSize === 0 && item.writeBehindFlushFrequency === 0)
-                return showPopoverMessage($scope.ui, 'store', 'writeBehindFlushSize', 'Both "Flush frequency" and "Flush size" are not allowed as 0!');
-
-            return true;
-        }
-
-        // Save cache in database.
-        function save(item) {
-            $http.post('/api/v1/configuration/caches/save', item)
-                .success(function(_id) {
-                    item.label = _cacheLbl(item);
-
-                    $scope.ui.inputForm.$setPristine();
-
-                    const idx = _.findIndex($scope.caches, function(cache) {
-                        return cache._id === _id;
-                    });
-
-                    if (idx >= 0)
-                        angular.merge($scope.caches[idx], item);
-                    else {
-                        item._id = _id;
-                        $scope.caches.push(item);
-                    }
-
-                    _.forEach($scope.clusters, (cluster) => {
-                        if (_.includes(item.clusters, cluster.value))
-                            cluster.caches = _.union(cluster.caches, [_id]);
-                        else
-                            _.remove(cluster.caches, (id) => id === _id);
-                    });
-
-                    _.forEach($scope.domains, (domain) => {
-                        if (_.includes(item.domains, domain.value))
-                            domain.meta.caches = _.union(domain.meta.caches, [_id]);
-                        else
-                            _.remove(domain.meta.caches, (id) => id === _id);
-                    });
-
-                    $scope.selectItem(item);
-
-                    Messages.showInfo('Cache "' + item.name + '" saved.');
-                })
-                .error(Messages.showError);
-        }
-
-        // Save cache.
-        $scope.saveItem = function() {
-            const item = $scope.backupItem;
-
-            angular.extend(item, LegacyUtils.autoCacheStoreConfiguration(item, cacheDomains(item)));
-
-            if (validate(item))
-                save(item);
-        };
-
-        function _cacheNames() {
-            return _.map($scope.caches, function(cache) {
-                return cache.name;
-            });
-        }
-
-        // Clone cache with new name.
-        $scope.cloneItem = function() {
-            if (validate($scope.backupItem)) {
-                Clone.confirm($scope.backupItem.name, _cacheNames()).then(function(newName) {
-                    const item = angular.copy($scope.backupItem);
-
-                    delete item._id;
-
-                    item.name = newName;
-
-                    delete item.sqlSchema;
-
-                    save(item);
-                });
-            }
-        };
-
-        // Remove cache from db.
-        $scope.removeItem = function() {
-            const selectedItem = $scope.selectedItem;
-
-            Confirm.confirm('Are you sure you want to remove cache: "' + selectedItem.name + '"?')
-                .then(function() {
-                    const _id = selectedItem._id;
-
-                    $http.post('/api/v1/configuration/caches/remove', {_id})
-                        .success(function() {
-                            Messages.showInfo('Cache has been removed: ' + selectedItem.name);
-
-                            const caches = $scope.caches;
-
-                            const 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.backupItem = emptyCache;
-                                    $scope.ui.inputForm.$setPristine();
-                                }
-
-                                _.forEach($scope.clusters, (cluster) => _.remove(cluster.caches, (id) => id === _id));
-                                _.forEach($scope.domains, (domain) => _.remove(domain.meta.caches, (id) => id === _id));
-                            }
-                        })
-                        .error(Messages.showError);
-                });
-        };
-
-        // Remove all caches from db.
-        $scope.removeAllItems = function() {
-            Confirm.confirm('Are you sure you want to remove all caches?')
-                .then(function() {
-                    $http.post('/api/v1/configuration/caches/remove/all')
-                        .success(function() {
-                            Messages.showInfo('All caches have been removed');
-
-                            $scope.caches = [];
-
-                            _.forEach($scope.clusters, (cluster) => cluster.caches = []);
-                            _.forEach($scope.domains, (domain) => domain.meta.caches = []);
-
-                            $scope.backupItem = emptyCache;
-                            $scope.ui.inputForm.$setPristine();
-                        })
-                        .error(Messages.showError);
-                });
-        };
-
-        $scope.resetAll = function() {
-            Confirm.confirm('Are you sure you want to undo all changes for current cache?')
-                .then(function() {
-                    $scope.backupItem = $scope.selectedItem ? angular.copy($scope.selectedItem) : prepareNewItem();
-                    $scope.ui.inputForm.$setPristine();
-                });
-        };
-    }
-]];

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/src/main/js/controllers/clusters-controller.js
----------------------------------------------------------------------
diff --git a/modules/web-console/src/main/js/controllers/clusters-controller.js b/modules/web-console/src/main/js/controllers/clusters-controller.js
deleted file mode 100644
index 5f86d08..0000000
--- a/modules/web-console/src/main/js/controllers/clusters-controller.js
+++ /dev/null
@@ -1,626 +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.
- */
-
-// Controller for Clusters screen.
-export default ['clustersController', [
-    '$rootScope', '$scope', '$http', '$state', '$timeout', 'IgniteLegacyUtils', 'IgniteMessages', 'IgniteConfirm', 'IgniteClone', 'IgniteLoading', 'IgniteModelNormalizer', 'IgniteUnsavedChangesGuard', 'igniteEventGroups', 'DemoInfo', 'IgniteLegacyTable',
-    function($root, $scope, $http, $state, $timeout, LegacyUtils, Messages, Confirm, Clone, Loading, ModelNormalizer, UnsavedChangesGuard, igniteEventGroups, DemoInfo, LegacyTable) {
-        UnsavedChangesGuard.install($scope);
-
-        const emptyCluster = {empty: true};
-
-        let __original_value;
-
-        const blank = {
-            atomicConfiguration: {},
-            binaryConfiguration: {},
-            communication: {},
-            connector: {},
-            discovery: {},
-            marshaller: {},
-            sslContextFactory: {},
-            swapSpaceSpi: {},
-            transactionConfiguration: {},
-            collision: {}
-        };
-
-        const pairFields = {
-            attributes: {id: 'Attribute', idPrefix: 'Key', searchCol: 'name', valueCol: 'key', dupObjName: 'name', group: 'attributes'},
-            'collision.JobStealing.stealingAttributes': {id: 'CAttribute', idPrefix: 'Key', searchCol: 'name', valueCol: 'key', dupObjName: 'name', group: 'collision'}
-        };
-
-        const showPopoverMessage = LegacyUtils.showPopoverMessage;
-
-        $scope.tablePairValid = function(item, field, index) {
-            const pairField = pairFields[field.model];
-
-            const pairValue = LegacyTable.tablePairValue(field, index);
-
-            if (pairField) {
-                const model = _.get(item, field.model);
-
-                if (LegacyUtils.isDefined(model)) {
-                    const idx = _.findIndex(model, (pair) => {
-                        return pair[pairField.searchCol] === pairValue[pairField.valueCol];
-                    });
-
-                    // Found duplicate by key.
-                    if (idx >= 0 && idx !== index)
-                        return showPopoverMessage($scope.ui, pairField.group, LegacyTable.tableFieldId(index, pairField.idPrefix + pairField.id), 'Attribute with such ' + pairField.dupObjName + ' already exists!');
-                }
-            }
-
-            return true;
-        };
-
-        $scope.tableSave = function(field, index, stopEdit) {
-            if (LegacyTable.tablePairSaveVisible(field, index))
-                return LegacyTable.tablePairSave($scope.tablePairValid, $scope.backupItem, field, index, stopEdit);
-
-            return true;
-        };
-
-        $scope.tableReset = (trySave) => {
-            const field = LegacyTable.tableField();
-
-            if (trySave && LegacyUtils.isDefined(field) && !$scope.tableSave(field, LegacyTable.tableEditedRowIndex(), true))
-                return false;
-
-            LegacyTable.tableReset();
-
-            return true;
-        };
-
-        $scope.tableNewItem = function(field) {
-            if ($scope.tableReset(true)) {
-                if (field.type === 'failoverSpi') {
-                    if (LegacyUtils.isDefined($scope.backupItem.failoverSpi))
-                        $scope.backupItem.failoverSpi.push({});
-                    else
-                        $scope.backupItem.failoverSpi = {};
-                }
-                else
-                    LegacyTable.tableNewItem(field);
-            }
-        };
-
-        $scope.tableNewItemActive = LegacyTable.tableNewItemActive;
-
-        $scope.tableStartEdit = function(item, field, index) {
-            if ($scope.tableReset(true))
-                LegacyTable.tableStartEdit(item, field, index, $scope.tableSave);
-        };
-
-        $scope.tableEditing = LegacyTable.tableEditing;
-
-        $scope.tableRemove = function(item, field, index) {
-            if ($scope.tableReset(true))
-                LegacyTable.tableRemove(item, field, index);
-        };
-
-        $scope.tablePairSave = LegacyTable.tablePairSave;
-        $scope.tablePairSaveVisible = LegacyTable.tablePairSaveVisible;
-
-        $scope.attributesTbl = {
-            type: 'attributes',
-            model: 'attributes',
-            focusId: 'Attribute',
-            ui: 'table-pair',
-            keyName: 'name',
-            valueName: 'value',
-            save: $scope.tableSave
-        };
-
-        $scope.stealingAttributesTbl = {
-            type: 'attributes',
-            model: 'collision.JobStealing.stealingAttributes',
-            focusId: 'CAttribute',
-            ui: 'table-pair',
-            keyName: 'name',
-            valueName: 'value',
-            save: $scope.tableSave
-        };
-
-        $scope.removeFailoverConfiguration = function(idx) {
-            $scope.backupItem.failoverSpi.splice(idx, 1);
-        };
-
-        // We need to initialize backupItem with empty object in order to properly used from angular directives.
-        $scope.backupItem = emptyCluster;
-
-        $scope.ui = LegacyUtils.formUI();
-        $scope.ui.activePanels = [0];
-        $scope.ui.topPanels = [0];
-
-        $scope.hidePopover = LegacyUtils.hidePopover;
-        $scope.saveBtnTipText = LegacyUtils.saveBtnTipText;
-        $scope.widthIsSufficient = LegacyUtils.widthIsSufficient;
-
-        $scope.contentVisible = function() {
-            const item = $scope.backupItem;
-
-            return !item.empty && (!item._id || _.find($scope.displayedRows, {_id: item._id}));
-        };
-
-        $scope.toggleExpanded = function() {
-            $scope.ui.expanded = !$scope.ui.expanded;
-
-            LegacyUtils.hidePopover();
-        };
-
-        $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'},
-            {value: 'ZooKeeper', label: 'Apache ZooKeeper'}
-        ];
-
-        $scope.swapSpaceSpis = [
-            {value: 'FileSwapSpaceSpi', label: 'File-based swap'},
-            {value: null, label: 'Not set'}
-        ];
-
-        $scope.eventGroups = igniteEventGroups;
-
-        $scope.clusters = [];
-
-        function _clusterLbl(cluster) {
-            return cluster.name + ', ' + _.find($scope.discoveries, {value: cluster.discovery.kind}).label;
-        }
-
-        function selectFirstItem() {
-            if ($scope.clusters.length > 0)
-                $scope.selectItem($scope.clusters[0]);
-        }
-
-        Loading.start('loadingClustersScreen');
-
-        // When landing on the page, get clusters and show them.
-        $http.post('/api/v1/configuration/clusters/list')
-            .success(function(data) {
-                $scope.spaces = data.spaces;
-                $scope.clusters = data.clusters;
-                $scope.caches = _.map(data.caches, (cache) => ({value: cache._id, label: cache.name, cache}));
-                $scope.igfss = _.map(data.igfss, (igfs) => ({value: igfs._id, label: igfs.name, igfs}));
-
-                _.forEach($scope.clusters, (cluster) => {
-                    cluster.label = _clusterLbl(cluster);
-
-                    if (!cluster.collision || !cluster.collision.kind)
-                        cluster.collision = {kind: 'Noop', JobStealing: {stealingEnabled: true}, PriorityQueue: {starvationPreventionEnabled: true}};
-
-                    if (!cluster.failoverSpi)
-                        cluster.failoverSpi = [];
-
-                    if (!cluster.logger)
-                        cluster.logger = {Log4j: { mode: 'Default'}};
-                });
-
-                if ($state.params.linkId)
-                    $scope.createItem($state.params.linkId);
-                else {
-                    const lastSelectedCluster = angular.fromJson(sessionStorage.lastSelectedCluster);
-
-                    if (lastSelectedCluster) {
-                        const idx = _.findIndex($scope.clusters, (cluster) => cluster._id === lastSelectedCluster);
-
-                        if (idx >= 0)
-                            $scope.selectItem($scope.clusters[idx]);
-                        else {
-                            sessionStorage.removeItem('lastSelectedCluster');
-
-                            selectFirstItem();
-                        }
-                    }
-                    else
-                        selectFirstItem();
-                }
-
-                $scope.$watch('ui.inputForm.$valid', function(valid) {
-                    if (valid && ModelNormalizer.isEqual(__original_value, $scope.backupItem))
-                        $scope.ui.inputForm.$dirty = false;
-                });
-
-                $scope.$watch('backupItem', function(val) {
-                    const form = $scope.ui.inputForm;
-
-                    if (form.$pristine || (form.$valid && ModelNormalizer.isEqual(__original_value, val)))
-                        form.$setPristine();
-                    else
-                        form.$setDirty();
-                }, true);
-
-                if ($root.IgniteDemoMode && sessionStorage.showDemoInfo !== 'true') {
-                    sessionStorage.showDemoInfo = 'true';
-
-                    DemoInfo.show();
-                }
-            })
-            .catch(Messages.showError)
-            .finally(function() {
-                $scope.ui.ready = true;
-                $scope.ui.inputForm.$setPristine();
-                Loading.finish('loadingClustersScreen');
-            });
-
-        $scope.selectItem = function(item, backup) {
-            function selectItem() {
-                $scope.selectedItem = item;
-
-                try {
-                    if (item && item._id)
-                        sessionStorage.lastSelectedCluster = angular.toJson(item._id);
-                    else
-                        sessionStorage.removeItem('lastSelectedCluster');
-                }
-                catch (ignored) {
-                    // No-op.
-                }
-
-                if (backup)
-                    $scope.backupItem = backup;
-                else if (item)
-                    $scope.backupItem = angular.copy(item);
-                else
-                    $scope.backupItem = emptyCluster;
-
-                $scope.backupItem = angular.merge({}, blank, $scope.backupItem);
-
-                __original_value = ModelNormalizer.normalize($scope.backupItem);
-
-                if (LegacyUtils.getQueryVariable('new'))
-                    $state.go('base.configuration.clusters');
-            }
-
-            LegacyUtils.confirmUnsavedChanges($scope.backupItem && $scope.ui.inputForm.$dirty, selectItem);
-        };
-
-        $scope.linkId = () => $scope.backupItem._id ? $scope.backupItem._id : 'create';
-
-        function prepareNewItem(linkId) {
-            return angular.merge({}, blank, {
-                space: $scope.spaces[0]._id,
-                discovery: {kind: 'Multicast', Vm: {addresses: ['127.0.0.1:47500..47510']}, Multicast: {addresses: ['127.0.0.1:47500..47510']}},
-                binaryConfiguration: {typeConfigurations: [], compactFooter: true},
-                communication: {tcpNoDelay: true},
-                connector: {noDelay: true},
-                collision: {kind: 'Noop', JobStealing: {stealingEnabled: true}, PriorityQueue: {starvationPreventionEnabled: true}},
-                failoverSpi: [],
-                logger: {Log4j: { mode: 'Default'}},
-                caches: linkId && _.find($scope.caches, {value: linkId}) ? [linkId] : [],
-                igfss: linkId && _.find($scope.igfss, {value: linkId}) ? [linkId] : []
-            });
-        }
-
-        // Add new cluster.
-        $scope.createItem = function(linkId) {
-            $timeout(() => LegacyUtils.ensureActivePanel($scope.ui, 'general', 'clusterName'));
-
-            $scope.selectItem(null, prepareNewItem(linkId));
-        };
-
-        $scope.indexOfCache = function(cacheId) {
-            return _.findIndex($scope.caches, (cache) => cache.value === cacheId);
-        };
-
-        function clusterCaches(item) {
-            return _.filter(_.map($scope.caches, (scopeCache) => scopeCache.cache),
-                (cache) => _.includes(item.caches, cache._id));
-        }
-
-        function checkCacheDatasources(item) {
-            const caches = clusterCaches(item);
-
-            const checkRes = LegacyUtils.checkCachesDataSources(caches);
-
-            if (!checkRes.checked) {
-                return showPopoverMessage($scope.ui, 'general', 'caches',
-                    'Found caches "' + checkRes.firstCache.name + '" and "' + checkRes.secondCache.name + '" ' +
-                    'with the same data source bean name "' + checkRes.firstCache.cacheStoreFactory[checkRes.firstCache.cacheStoreFactory.kind].dataSourceBean +
-                    '" and different databases: "' + LegacyUtils.cacheStoreJdbcDialectsLabel(checkRes.firstDB) + '" in "' + checkRes.firstCache.name + '" and "' +
-                    LegacyUtils.cacheStoreJdbcDialectsLabel(checkRes.secondDB) + '" in "' + checkRes.secondCache.name + '"', 10000);
-            }
-
-            return true;
-        }
-
-        function checkCacheSQLSchemas(item) {
-            const caches = clusterCaches(item);
-
-            const checkRes = LegacyUtils.checkCacheSQLSchemas(caches);
-
-            if (!checkRes.checked) {
-                return showPopoverMessage($scope.ui, 'general', 'caches',
-                    'Found caches "' + checkRes.firstCache.name + '" and "' + checkRes.secondCache.name + '" ' +
-                    'with the same SQL schema name "' + checkRes.firstCache.sqlSchema + '"', 10000);
-            }
-
-            return true;
-        }
-
-        function checkBinaryConfiguration(item) {
-            const b = item.binaryConfiguration;
-
-            if (LegacyUtils.isDefined(b)) {
-                if (!_.isEmpty(b.typeConfigurations)) {
-                    for (let typeIx = 0; typeIx < b.typeConfigurations.length; typeIx++) {
-                        const type = b.typeConfigurations[typeIx];
-
-                        if (LegacyUtils.isEmptyString(type.typeName))
-                            return showPopoverMessage($scope.ui, 'binary', 'typeName' + typeIx, 'Type name should be specified!');
-
-                        if (_.find(b.typeConfigurations, (t, ix) => ix < typeIx && t.typeName === type.typeName))
-                            return showPopoverMessage($scope.ui, 'binary', 'typeName' + typeIx, 'Type with such name is already specified!');
-                    }
-                }
-            }
-
-            return true;
-        }
-
-        function checkCommunicationConfiguration(item) {
-            const c = item.communication;
-
-            if (LegacyUtils.isDefined(c)) {
-                if (LegacyUtils.isDefined(c.unacknowledgedMessagesBufferSize)) {
-                    if (LegacyUtils.isDefined(c.messageQueueLimit) && c.unacknowledgedMessagesBufferSize < 5 * c.messageQueueLimit)
-                        return showPopoverMessage($scope.ui, 'communication', 'unacknowledgedMessagesBufferSize', 'Maximum number of stored unacknowledged messages should be at least 5 * message queue limit!');
-
-                    if (LegacyUtils.isDefined(c.ackSendThreshold) && c.unacknowledgedMessagesBufferSize < 5 * c.ackSendThreshold)
-                        return showPopoverMessage($scope.ui, 'communication', 'unacknowledgedMessagesBufferSize', 'Maximum number of stored unacknowledged messages should be at least 5 * ack send threshold!');
-                }
-
-                if (c.sharedMemoryPort === 0)
-                    return showPopoverMessage($scope.ui, 'communication', 'sharedMemoryPort', 'Shared memory port should be more than "0" or equals to "-1"!');
-            }
-
-            return true;
-        }
-
-        function checkDiscoveryConfiguration(item) {
-            const d = item.discovery;
-
-            if (d) {
-                if ((_.isNil(d.maxAckTimeout) ? 600000 : d.maxAckTimeout) < (d.ackTimeout || 5000))
-                    return showPopoverMessage($scope.ui, 'discovery', 'ackTimeout', 'Acknowledgement timeout should be less than max acknowledgement timeout!');
-
-                if (d.kind === 'Vm' && d.Vm && d.Vm.addresses.length === 0)
-                    return showPopoverMessage($scope.ui, 'general', 'addresses', 'Addresses are not specified!');
-            }
-
-            return true;
-        }
-
-        function checkSwapConfiguration(item) {
-            const swapKind = item.swapSpaceSpi && item.swapSpaceSpi.kind;
-
-            if (swapKind && item.swapSpaceSpi[swapKind]) {
-                const swap = item.swapSpaceSpi[swapKind];
-
-                const sparsity = swap.maximumSparsity;
-
-                if (LegacyUtils.isDefined(sparsity) && (sparsity < 0 || sparsity >= 1))
-                    return showPopoverMessage($scope.ui, 'swap', 'maximumSparsity', 'Maximum sparsity should be more or equal 0 and less than 1!');
-
-                const readStripesNumber = swap.readStripesNumber;
-
-                if (readStripesNumber && !(readStripesNumber === -1 || (readStripesNumber & (readStripesNumber - 1)) === 0))
-                    return showPopoverMessage($scope.ui, 'swap', 'readStripesNumber', 'Read stripe size must be positive and power of two!');
-            }
-
-            return true;
-        }
-
-        function checkSslConfiguration(item) {
-            const r = item.connector;
-
-            if (LegacyUtils.isDefined(r)) {
-                if (r.sslEnabled && LegacyUtils.isEmptyString(r.sslFactory))
-                    return showPopoverMessage($scope.ui, 'connector', 'connectorSslFactory', 'SSL factory should not be empty!');
-            }
-
-            if (item.sslEnabled) {
-                if (!LegacyUtils.isDefined(item.sslContextFactory) || LegacyUtils.isEmptyString(item.sslContextFactory.keyStoreFilePath))
-                    return showPopoverMessage($scope.ui, 'sslConfiguration', 'keyStoreFilePath', 'Key store file should not be empty!');
-
-                if (LegacyUtils.isEmptyString(item.sslContextFactory.trustStoreFilePath) && _.isEmpty(item.sslContextFactory.trustManagers))
-                    return showPopoverMessage($scope.ui, 'sslConfiguration', 'sslConfiguration-title', 'Trust storage file or managers should be configured!');
-            }
-
-            return true;
-        }
-
-        function checkPoolSizes(item) {
-            if (item.rebalanceThreadPoolSize && item.systemThreadPoolSize && item.systemThreadPoolSize <= item.rebalanceThreadPoolSize)
-                return showPopoverMessage($scope.ui, 'pools', 'rebalanceThreadPoolSize', 'Rebalance thread pool size exceed or equals System thread pool size!');
-
-            return true;
-        }
-
-        // Check cluster logical consistency.
-        function validate(item) {
-            LegacyUtils.hidePopover();
-
-            if (LegacyUtils.isEmptyString(item.name))
-                return showPopoverMessage($scope.ui, 'general', 'clusterName', 'Cluster name should not be empty!');
-
-            if (!LegacyUtils.checkFieldValidators($scope.ui))
-                return false;
-
-            if (!checkCacheSQLSchemas(item))
-                return false;
-
-            if (!checkCacheDatasources(item))
-                return false;
-
-            if (!checkBinaryConfiguration(item))
-                return false;
-
-            if (!checkCommunicationConfiguration(item))
-                return false;
-
-            if (!checkDiscoveryConfiguration(item))
-                return false;
-
-            if (!checkSwapConfiguration(item))
-                return false;
-
-            if (!checkSslConfiguration(item))
-                return false;
-
-            if (!checkPoolSizes(item))
-                return false;
-
-            return true;
-        }
-
-        // Save cluster in database.
-        function save(item) {
-            $http.post('/api/v1/configuration/clusters/save', item)
-                .success(function(_id) {
-                    item.label = _clusterLbl(item);
-
-                    $scope.ui.inputForm.$setPristine();
-
-                    const idx = _.findIndex($scope.clusters, (cluster) => cluster._id === _id);
-
-                    if (idx >= 0)
-                        angular.merge($scope.clusters[idx], item);
-                    else {
-                        item._id = _id;
-                        $scope.clusters.push(item);
-                    }
-
-                    _.forEach($scope.caches, (cache) => {
-                        if (_.includes(item.caches, cache.value))
-                            cache.cache.clusters = _.union(cache.cache.clusters, [_id]);
-                        else
-                            _.remove(cache.cache.clusters, (id) => id === _id);
-                    });
-
-                    _.forEach($scope.igfss, (igfs) => {
-                        if (_.includes(item.igfss, igfs.value))
-                            igfs.igfs.clusters = _.union(igfs.igfs.clusters, [_id]);
-                        else
-                            _.remove(igfs.igfs.clusters, (id) => id === _id);
-                    });
-
-                    $scope.selectItem(item);
-
-                    Messages.showInfo('Cluster "' + item.name + '" saved.');
-                })
-                .error(Messages.showError);
-        }
-
-        // Save cluster.
-        $scope.saveItem = function() {
-            const item = $scope.backupItem;
-
-            const swapSpi = LegacyUtils.autoClusterSwapSpiConfiguration(item, clusterCaches(item));
-
-            if (swapSpi)
-                angular.extend(item, swapSpi);
-
-            if (validate(item))
-                save(item);
-        };
-
-        function _clusterNames() {
-            return _.map($scope.clusters, (cluster) => cluster.name);
-        }
-
-        // Clone cluster with new name.
-        $scope.cloneItem = function() {
-            if (validate($scope.backupItem)) {
-                Clone.confirm($scope.backupItem.name, _clusterNames()).then(function(newName) {
-                    const item = angular.copy($scope.backupItem);
-
-                    delete item._id;
-                    item.name = newName;
-
-                    save(item);
-                });
-            }
-        };
-
-        // Remove cluster from db.
-        $scope.removeItem = function() {
-            const selectedItem = $scope.selectedItem;
-
-            Confirm.confirm('Are you sure you want to remove cluster: "' + selectedItem.name + '"?')
-                .then(function() {
-                    const _id = selectedItem._id;
-
-                    $http.post('/api/v1/configuration/clusters/remove', {_id})
-                        .success(function() {
-                            Messages.showInfo('Cluster has been removed: ' + selectedItem.name);
-
-                            const clusters = $scope.clusters;
-
-                            const idx = _.findIndex(clusters, (cluster) => cluster._id === _id);
-
-                            if (idx >= 0) {
-                                clusters.splice(idx, 1);
-
-                                if (clusters.length > 0)
-                                    $scope.selectItem(clusters[0]);
-                                else {
-                                    $scope.backupItem = emptyCluster;
-                                    $scope.ui.inputForm.$setPristine();
-                                }
-
-                                _.forEach($scope.caches, (cache) => _.remove(cache.cache.clusters, (id) => id === _id));
-                                _.forEach($scope.igfss, (igfs) => _.remove(igfs.igfs.clusters, (id) => id === _id));
-                            }
-                        })
-                        .error(Messages.showError);
-                });
-        };
-
-        // Remove all clusters from db.
-        $scope.removeAllItems = function() {
-            Confirm.confirm('Are you sure you want to remove all clusters?')
-                .then(function() {
-                    $http.post('/api/v1/configuration/clusters/remove/all')
-                        .success(() => {
-                            Messages.showInfo('All clusters have been removed');
-
-                            $scope.clusters = [];
-
-                            _.forEach($scope.caches, (cache) => cache.cache.clusters = []);
-                            _.forEach($scope.igfss, (igfs) => igfs.igfs.clusters = []);
-
-                            $scope.backupItem = emptyCluster;
-                            $scope.ui.inputForm.$setPristine();
-                        })
-                        .error(Messages.showError);
-                });
-        };
-
-        $scope.resetAll = function() {
-            Confirm.confirm('Are you sure you want to undo all changes for current cluster?')
-                .then(function() {
-                    $scope.backupItem = $scope.selectedItem ? angular.copy($scope.selectedItem) : prepareNewItem();
-                    $scope.ui.inputForm.$setPristine();
-                });
-        };
-    }
-]];


[11/52] ignite git commit: Web Console beta-3.

Posted by ak...@apache.org.
http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/src/main/js/controllers/domains-controller.js
----------------------------------------------------------------------
diff --git a/modules/web-console/src/main/js/controllers/domains-controller.js b/modules/web-console/src/main/js/controllers/domains-controller.js
deleted file mode 100644
index cfb539d..0000000
--- a/modules/web-console/src/main/js/controllers/domains-controller.js
+++ /dev/null
@@ -1,1746 +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.
- */
-
-// Controller for Domain model screen.
-export default ['domainsController', [
-    '$rootScope', '$scope', '$http', '$state', '$filter', '$timeout', '$modal', 'IgniteLegacyUtils', 'IgniteMessages', 'IgniteFocus', 'IgniteConfirm', 'IgniteConfirmBatch', 'IgniteClone', 'IgniteLoading', 'IgniteModelNormalizer', 'IgniteUnsavedChangesGuard', 'IgniteAgentMonitor', 'IgniteLegacyTable',
-    function($root, $scope, $http, $state, $filter, $timeout, $modal, LegacyUtils, Messages, Focus, Confirm, ConfirmBatch, Clone, Loading, ModelNormalizer, UnsavedChangesGuard, IgniteAgentMonitor, LegacyTable) {
-        UnsavedChangesGuard.install($scope);
-
-        const emptyDomain = {empty: true};
-
-        let __original_value;
-
-        const blank = {};
-
-        // We need to initialize backupItem with empty object in order to properly used from angular directives.
-        $scope.backupItem = emptyDomain;
-
-        $scope.ui = LegacyUtils.formUI();
-        $scope.ui.activePanels = [0, 1];
-        $scope.ui.topPanels = [0, 1, 2];
-
-        const IMPORT_DM_NEW_CACHE = 1;
-        const IMPORT_DM_ASSOCIATE_CACHE = 2;
-
-        /**
-         * Convert some name to valid java package name.
-         *
-         * @param name to convert.
-         * @returns {string} Valid java package name.
-         */
-        const _toJavaPackage = (name) => {
-            return name ? name.replace(/[^A-Za-z_0-9/.]+/g, '_') : 'org';
-        };
-
-        $scope.ui.packageNameUserInput = $scope.ui.packageName =
-            _toJavaPackage($root.user.email.replace('@', '.').split('.').reverse().join('.') + '.model');
-        $scope.ui.builtinKeys = true;
-        $scope.ui.usePrimitives = true;
-        $scope.ui.generateAliases = true;
-        $scope.ui.generatedCachesClusters = [];
-
-        function _mapCaches(caches) {
-            return _.map(caches, (cache) => {
-                return {label: cache.name, value: cache._id, cache};
-            });
-        }
-
-        $scope.contentVisible = function() {
-            const item = $scope.backupItem;
-
-            return !item.empty && (!item._id || _.find($scope.displayedRows, {_id: item._id}));
-        };
-
-        $scope.getModel = LegacyUtils.getModel;
-        $scope.javaBuiltInClasses = LegacyUtils.javaBuiltInClasses;
-        $scope.compactJavaName = LegacyUtils.compactJavaName;
-        $scope.widthIsSufficient = LegacyUtils.widthIsSufficient;
-        $scope.saveBtnTipText = LegacyUtils.saveBtnTipText;
-
-        $scope.tableSave = function(field, index, stopEdit) {
-            if (LegacyTable.tableEditing({model: 'table-index-fields'}, LegacyTable.tableEditedRowIndex())) {
-                if ($scope.tableIndexItemSaveVisible(field, index))
-                    return $scope.tableIndexItemSave(field, field.indexIdx, index, stopEdit);
-            }
-            else {
-                switch (field.type) {
-                    case 'fields':
-                    case 'aliases':
-                        if (LegacyTable.tablePairSaveVisible(field, index))
-                            return LegacyTable.tablePairSave($scope.tablePairValid, $scope.backupItem, field, index, stopEdit);
-
-                        break;
-
-                    case 'indexes':
-                        if ($scope.tableIndexSaveVisible(field, index))
-                            return $scope.tableIndexSave(field, index, stopEdit);
-
-                        break;
-
-                    case 'table-db-fields':
-                        if ($scope.tableDbFieldSaveVisible(field, index))
-                            return $scope.tableDbFieldSave(field, index, stopEdit);
-
-                        break;
-
-                    default:
-                }
-            }
-
-            return true;
-        };
-
-        $scope.tableReset = (trySave) => {
-            const field = LegacyTable.tableField();
-
-            if (trySave && LegacyUtils.isDefined(field) && !$scope.tableSave(field, LegacyTable.tableEditedRowIndex(), true))
-                return false;
-
-            LegacyTable.tableReset();
-
-            return true;
-        };
-
-        $scope.tableNewItem = function(field) {
-            if ($scope.tableReset(true))
-                LegacyTable.tableNewItem(field);
-        };
-
-        $scope.tableNewItemActive = LegacyTable.tableNewItemActive;
-
-        $scope.tableStartEdit = function(item, field, index) {
-            if ($scope.tableReset(true))
-                LegacyTable.tableStartEdit(item, field, index, $scope.tableSave);
-        };
-
-        $scope.tableEditing = LegacyTable.tableEditing;
-
-        $scope.tableRemove = function(item, field, index) {
-            if ($scope.tableReset(true))
-                LegacyTable.tableRemove(item, field, index);
-        };
-
-        $scope.tablePairSave = LegacyTable.tablePairSave;
-        $scope.tablePairSaveVisible = LegacyTable.tablePairSaveVisible;
-
-        $scope.queryFieldsTbl = {
-            type: 'fields',
-            model: 'fields',
-            focusId: 'QryField',
-            ui: 'table-pair',
-            keyName: 'name',
-            valueName: 'className',
-            save: $scope.tableSave
-        };
-
-        $scope.aliasesTbl = {
-            type: 'aliases',
-            model: 'aliases',
-            focusId: 'Alias',
-            ui: 'table-pair',
-            keyName: 'field',
-            valueName: 'alias',
-            save: $scope.tableSave
-        };
-
-        $scope.queryMetadataVariants = LegacyUtils.mkOptions(['Annotations', 'Configuration']);
-
-        const INFO_CONNECT_TO_DB = 'Configure connection to database';
-        const INFO_SELECT_SCHEMAS = 'Select schemas to load tables from';
-        const INFO_SELECT_TABLES = 'Select tables to import as domain model';
-        const INFO_SELECT_OPTIONS = 'Select import domain model options';
-        const LOADING_JDBC_DRIVERS = {text: 'Loading JDBC drivers...'};
-        const LOADING_SCHEMAS = {text: 'Loading schemas...'};
-        const LOADING_TABLES = {text: 'Loading tables...'};
-        const SAVING_DOMAINS = {text: 'Saving domain model...'};
-
-        $scope.ui.invalidKeyFieldsTooltip = 'Found key types without configured key fields<br/>' +
-            'It may be a result of import tables from database without primary keys<br/>' +
-            'Key field for such key types should be configured manually';
-
-        $scope.hidePopover = LegacyUtils.hidePopover;
-
-        const showPopoverMessage = LegacyUtils.showPopoverMessage;
-
-        $scope.indexType = LegacyUtils.mkOptions(['SORTED', 'FULLTEXT', 'GEOSPATIAL']);
-
-        const _dbPresets = [
-            {
-                db: 'Oracle',
-                jdbcDriverClass: 'oracle.jdbc.OracleDriver',
-                jdbcUrl: 'jdbc:oracle:thin:@[host]:[port]:[database]',
-                user: 'system'
-            },
-            {
-                db: 'DB2',
-                jdbcDriverClass: 'com.ibm.db2.jcc.DB2Driver',
-                jdbcUrl: 'jdbc:db2://[host]:[port]/[database]',
-                user: 'db2admin'
-            },
-            {
-                db: 'SQLServer',
-                jdbcDriverClass: 'com.microsoft.sqlserver.jdbc.SQLServerDriver',
-                jdbcUrl: 'jdbc:sqlserver://[host]:[port][;databaseName=database]'
-            },
-            {
-                db: 'PostgreSQL',
-                jdbcDriverClass: 'org.postgresql.Driver',
-                jdbcUrl: 'jdbc:postgresql://[host]:[port]/[database]',
-                user: 'sa'
-            },
-            {
-                db: 'MySQL',
-                jdbcDriverClass: 'com.mysql.jdbc.Driver',
-                jdbcUrl: 'jdbc:mysql://[host]:[port]/[database]',
-                user: 'root'
-            },
-            {
-                db: 'H2',
-                jdbcDriverClass: 'org.h2.Driver',
-                jdbcUrl: 'jdbc:h2:tcp://[host]/[database]',
-                user: 'sa'
-            }
-        ];
-
-        $scope.selectedPreset = {
-            db: 'General',
-            jdbcDriverJar: '',
-            jdbcDriverClass: '',
-            jdbcUrl: 'jdbc:[database]',
-            user: 'sa',
-            password: '',
-            tablesOnly: true
-        };
-
-        $scope.demoConnection = {
-            db: 'H2',
-            jdbcDriverClass: 'org.h2.Driver',
-            jdbcUrl: 'jdbc:h2:mem:demo-db',
-            user: 'sa',
-            password: '',
-            tablesOnly: true
-        };
-
-        function _loadPresets() {
-            try {
-                const restoredPresets = JSON.parse(localStorage.dbPresets);
-
-                _.forEach(restoredPresets, (restoredPreset) => {
-                    const preset = _.find(_dbPresets, {jdbcDriverClass: restoredPreset.jdbcDriverClass});
-
-                    if (preset) {
-                        preset.jdbcUrl = restoredPreset.jdbcUrl;
-                        preset.user = restoredPreset.user;
-                    }
-                });
-            }
-            catch (ignore) {
-                // No-op.
-            }
-        }
-
-        _loadPresets();
-
-        function _savePreset(preset) {
-            try {
-                const oldPreset = _.find(_dbPresets, {jdbcDriverClass: preset.jdbcDriverClass});
-
-                if (oldPreset)
-                    angular.extend(oldPreset, preset);
-                else
-                    _dbPresets.push(preset);
-
-                localStorage.dbPresets = JSON.stringify(_dbPresets);
-            }
-            catch (err) {
-                Messages.showError(err);
-            }
-        }
-
-        function _findPreset(selectedJdbcJar) {
-            let result = _.find(_dbPresets, function(preset) {
-                return preset.jdbcDriverClass === selectedJdbcJar.jdbcDriverClass;
-            });
-
-            if (!result)
-                result = {db: 'General', jdbcUrl: 'jdbc:[database]', user: 'admin'};
-
-            result.jdbcDriverJar = selectedJdbcJar.jdbcDriverJar;
-            result.jdbcDriverClass = selectedJdbcJar.jdbcDriverClass;
-
-            return result;
-        }
-
-        $scope.$watch('ui.selectedJdbcDriverJar', function(val) {
-            if (val && !$scope.importDomain.demo) {
-                const foundPreset = _findPreset(val);
-
-                const selectedPreset = $scope.selectedPreset;
-
-                selectedPreset.db = foundPreset.db;
-                selectedPreset.jdbcDriverJar = foundPreset.jdbcDriverJar;
-                selectedPreset.jdbcDriverClass = foundPreset.jdbcDriverClass;
-                selectedPreset.jdbcUrl = foundPreset.jdbcUrl;
-                selectedPreset.user = foundPreset.user;
-            }
-        }, true);
-
-        $scope.ui.showValid = true;
-
-        $scope.supportedJdbcTypes = LegacyUtils.mkOptions(LegacyUtils.SUPPORTED_JDBC_TYPES);
-
-        $scope.supportedJavaTypes = LegacyUtils.mkOptions(LegacyUtils.javaBuiltInTypes);
-
-        $scope.sortDirections = [
-            {value: true, label: 'ASC'},
-            {value: false, label: 'DESC'}
-        ];
-
-        $scope.domains = [];
-
-        $scope.isJavaBuiltInClass = function() {
-            const item = $scope.backupItem;
-
-            if (item && item.keyType)
-                return LegacyUtils.isJavaBuiltInClass(item.keyType);
-
-            return false;
-        };
-
-        $scope.selectAllSchemas = function() {
-            const allSelected = $scope.importDomain.allSchemasSelected;
-
-            _.forEach($scope.importDomain.displayedSchemas, (schema) => schema.use = allSelected);
-        };
-
-        $scope.selectSchema = function() {
-            if (LegacyUtils.isDefined($scope.importDomain) && LegacyUtils.isDefined($scope.importDomain.displayedSchemas))
-                $scope.importDomain.allSchemasSelected = $scope.importDomain.displayedSchemas.length > 0 && _.every($scope.importDomain.displayedSchemas, 'use', true);
-        };
-
-        $scope.selectAllTables = function() {
-            const allSelected = $scope.importDomain.allTablesSelected;
-
-            _.forEach($scope.importDomain.displayedTables, function(table) {
-                table.use = allSelected;
-            });
-        };
-
-        $scope.selectTable = function() {
-            if (LegacyUtils.isDefined($scope.importDomain) && LegacyUtils.isDefined($scope.importDomain.displayedTables))
-                $scope.importDomain.allTablesSelected = $scope.importDomain.displayedTables.length > 0 && _.every($scope.importDomain.displayedTables, 'use', true);
-        };
-
-        $scope.$watch('importDomain.displayedSchemas', $scope.selectSchema);
-
-        $scope.$watch('importDomain.displayedTables', $scope.selectTable);
-
-        // Pre-fetch modal dialogs.
-        const importDomainModal = $modal({scope: $scope, templateUrl: '/configuration/domains-import.html', show: false});
-
-        const hideImportDomain = importDomainModal.hide;
-
-        importDomainModal.hide = function() {
-            IgniteAgentMonitor.stopWatch();
-
-            hideImportDomain();
-        };
-
-        $scope.linkId = () => $scope.backupItem._id ? $scope.backupItem._id : 'create';
-
-        function prepareNewItem(cacheId) {
-            return {
-                space: $scope.spaces[0]._id,
-                caches: cacheId && _.find($scope.caches, {value: cacheId}) ? [cacheId] : // eslint-disable-line no-nested-ternary
-                    (_.isEmpty($scope.caches) ? [] : [$scope.caches[0].value]),
-                queryMetadata: 'Configuration'
-            };
-        }
-
-        /**
-         * Show import domain models modal.
-         */
-        $scope.showImportDomainModal = function() {
-            LegacyTable.tableReset();
-
-            LegacyUtils.confirmUnsavedChanges($scope.ui.inputForm.$dirty, function() {
-                if ($scope.ui.inputForm.$dirty)
-                    $scope.backupItem = $scope.selectedItem ? angular.copy($scope.selectedItem) : prepareNewItem();
-
-                const demo = $root.IgniteDemoMode;
-
-                $scope.importDomain = {
-                    demo,
-                    action: demo ? 'connect' : 'drivers',
-                    jdbcDriversNotFound: demo,
-                    schemas: [],
-                    allSchemasSelected: false,
-                    tables: [],
-                    allTablesSelected: false,
-                    button: 'Next',
-                    info: ''
-                };
-
-                $scope.importDomain.loadingOptions = LOADING_JDBC_DRIVERS;
-
-                IgniteAgentMonitor.startWatch({text: 'Back to Domain models', goal: 'import domain model from database'})
-                    .then(function() {
-                        importDomainModal.$promise.then(importDomainModal.show);
-
-                        if (demo) {
-                            $scope.ui.packageNameUserInput = $scope.ui.packageName;
-                            $scope.ui.packageName = 'model';
-
-                            return;
-                        }
-
-                        // Get available JDBC drivers via agent.
-                        Loading.start('importDomainFromDb');
-
-                        $scope.jdbcDriverJars = [];
-                        $scope.ui.selectedJdbcDriverJar = {};
-
-                        return IgniteAgentMonitor.drivers()
-                            .then(function(drivers) {
-                                $scope.ui.packageName = $scope.ui.packageNameUserInput;
-
-                                if (drivers && drivers.length > 0) {
-                                    drivers = _.sortBy(drivers, 'jdbcDriverJar');
-
-                                    _.forEach(drivers, function(drv) {
-                                        $scope.jdbcDriverJars.push({
-                                            label: drv.jdbcDriverJar,
-                                            value: {
-                                                jdbcDriverJar: drv.jdbcDriverJar,
-                                                jdbcDriverClass: drv.jdbcDriverCls
-                                            }
-                                        });
-                                    });
-
-                                    $scope.ui.selectedJdbcDriverJar = $scope.jdbcDriverJars[0].value;
-
-                                    LegacyUtils.confirmUnsavedChanges($scope.ui.inputForm.$dirty, function() {
-                                        importDomainModal.$promise.then(() => {
-                                            $scope.importDomain.action = 'connect';
-                                            $scope.importDomain.tables = [];
-
-                                            Focus.move('jdbcUrl');
-                                        });
-                                    });
-                                }
-                                else {
-                                    $scope.importDomain.jdbcDriversNotFound = true;
-                                    $scope.importDomain.button = 'Cancel';
-                                }
-                            })
-                            .finally(function() {
-                                $scope.importDomain.info = INFO_CONNECT_TO_DB;
-
-                                Loading.finish('importDomainFromDb');
-                            });
-                    });
-            });
-        };
-
-        /**
-         * Load list of database schemas.
-         */
-        function _loadSchemas() {
-            IgniteAgentMonitor.awaitAgent()
-                .then(function() {
-                    $scope.importDomain.loadingOptions = LOADING_SCHEMAS;
-                    Loading.start('importDomainFromDb');
-
-                    if ($root.IgniteDemoMode)
-                        return IgniteAgentMonitor.schemas($scope.demoConnection);
-
-                    const preset = $scope.selectedPreset;
-
-                    _savePreset(preset);
-
-                    return IgniteAgentMonitor.schemas(preset);
-                })
-                .then(function(schemas) {
-                    $scope.importDomain.schemas = _.map(schemas, function(schema) {
-                        return {use: true, name: schema};
-                    });
-
-                    $scope.importDomain.action = 'schemas';
-
-                    if ($scope.importDomain.schemas.length === 0)
-                        $scope.importDomainNext();
-
-                    $scope.importDomain.info = INFO_SELECT_SCHEMAS;
-                })
-                .catch(Messages.showError)
-                .finally(() => Loading.finish('importDomainFromDb'));
-        }
-
-        const DFLT_PARTITIONED_CACHE = {
-            label: 'PARTITIONED',
-            value: -1,
-            cache: {
-                name: 'PARTITIONED',
-                cacheMode: 'PARTITIONED',
-                atomicityMode: 'ATOMIC',
-                readThrough: true,
-                writeThrough: true
-            }
-        };
-
-        const DFLT_REPLICATED_CACHE = {
-            label: 'REPLICATED',
-            value: -2,
-            cache: {
-                name: 'REPLICATED',
-                cacheMode: 'REPLICATED',
-                atomicityMode: 'ATOMIC',
-                readThrough: true,
-                writeThrough: true
-            }
-        };
-
-        let _importCachesOrTemplates = [];
-
-        $scope.tableActionView = function(tbl) {
-            const cacheName = _.find(_importCachesOrTemplates, {value: tbl.cacheOrTemplate}).label;
-
-            if (tbl.action === IMPORT_DM_NEW_CACHE)
-                return 'Create ' + tbl.generatedCacheName + ' (' + cacheName + ')';
-
-            return 'Associate with ' + cacheName;
-        };
-
-        function toJavaClassName(name) {
-            const len = name.length;
-
-            let buf = '';
-
-            let capitalizeNext = true;
-
-            for (let i = 0; i < len; i++) {
-                const ch = name.charAt(i);
-
-                if (ch === ' ' || ch === '_')
-                    capitalizeNext = true;
-                else if (capitalizeNext) {
-                    buf += ch.toLocaleUpperCase();
-
-                    capitalizeNext = false;
-                }
-                else
-                    buf += ch.toLocaleLowerCase();
-            }
-
-            return buf;
-        }
-
-        function toJavaName(dbName) {
-            const javaName = toJavaClassName(dbName);
-
-            return javaName.charAt(0).toLocaleLowerCase() + javaName.slice(1);
-        }
-
-        function _fillCommonCachesOrTemplates(item) {
-            return function(action) {
-                if (item.cachesOrTemplates)
-                    item.cachesOrTemplates.length = 0;
-                else
-                    item.cachesOrTemplates = [];
-
-                if (action === IMPORT_DM_NEW_CACHE) {
-                    item.cachesOrTemplates.push(DFLT_PARTITIONED_CACHE);
-                    item.cachesOrTemplates.push(DFLT_REPLICATED_CACHE);
-                }
-
-                if (!_.isEmpty($scope.caches)) {
-                    if (item.cachesOrTemplates.length > 0)
-                        item.cachesOrTemplates.push(null);
-
-                    _.forEach($scope.caches, function(cache) {
-                        item.cachesOrTemplates.push(cache);
-                    });
-                }
-
-                if (!_.find(item.cachesOrTemplates, {value: item.cacheOrTemplate}))
-                    item.cacheOrTemplate = item.cachesOrTemplates[0].value;
-            };
-        }
-        /**
-         * Load list of database tables.
-         */
-        function _loadTables() {
-            IgniteAgentMonitor.awaitAgent()
-                .then(function() {
-                    $scope.importDomain.loadingOptions = LOADING_TABLES;
-                    Loading.start('importDomainFromDb');
-
-                    $scope.importDomain.allTablesSelected = false;
-
-                    const preset = $scope.importDomain.demo ? $scope.demoConnection : $scope.selectedPreset;
-
-                    preset.schemas = [];
-
-                    _.forEach($scope.importDomain.schemas, function(schema) {
-                        if (schema.use)
-                            preset.schemas.push(schema.name);
-                    });
-
-                    return IgniteAgentMonitor.tables(preset);
-                })
-                .then(function(tables) {
-                    _importCachesOrTemplates = [DFLT_PARTITIONED_CACHE, DFLT_REPLICATED_CACHE].concat($scope.caches);
-
-                    _fillCommonCachesOrTemplates($scope.importCommon)($scope.importCommon.action);
-
-                    _.forEach(tables, function(tbl, idx) {
-                        tbl.id = idx;
-                        tbl.action = IMPORT_DM_NEW_CACHE;
-                        tbl.generatedCacheName = toJavaClassName(tbl.tbl) + 'Cache';
-                        tbl.cacheOrTemplate = DFLT_PARTITIONED_CACHE.value;
-                        tbl.label = tbl.schema + '.' + tbl.tbl;
-                        tbl.edit = false;
-                        tbl.use = LegacyUtils.isDefined(_.find(tbl.cols, function(col) {
-                            return col.key;
-                        }));
-                    });
-
-                    $scope.importDomain.action = 'tables';
-                    $scope.importDomain.tables = tables;
-                    $scope.importDomain.info = INFO_SELECT_TABLES;
-                })
-                .catch(Messages.showError)
-                .finally(() => Loading.finish('importDomainFromDb'));
-        }
-
-        $scope.applyDefaults = function() {
-            _.forEach($scope.importDomain.displayedTables, function(table) {
-                table.edit = false;
-                table.action = $scope.importCommon.action;
-                table.cacheOrTemplate = $scope.importCommon.cacheOrTemplate;
-            });
-        };
-
-        $scope._curDbTable = null;
-
-        $scope.startEditDbTableCache = function(tbl) {
-            if ($scope._curDbTable) {
-                $scope._curDbTable.edit = false;
-
-                if ($scope._curDbTable.actionWatch) {
-                    $scope._curDbTable.actionWatch();
-
-                    $scope._curDbTable.actionWatch = null;
-                }
-            }
-
-            $scope._curDbTable = tbl;
-
-            const _fillFn = _fillCommonCachesOrTemplates($scope._curDbTable);
-
-            _fillFn($scope._curDbTable.action);
-
-            $scope._curDbTable.actionWatch = $scope.$watch('_curDbTable.action', _fillFn, true);
-
-            $scope._curDbTable.edit = true;
-        };
-
-        /**
-         * Show page with import domain models options.
-         */
-        function _selectOptions() {
-            $scope.importDomain.action = 'options';
-            $scope.importDomain.button = 'Save';
-            $scope.importDomain.info = INFO_SELECT_OPTIONS;
-
-            Focus.move('domainPackageName');
-        }
-
-        function _saveBatch(batch) {
-            if (batch && batch.length > 0) {
-                $scope.importDomain.loadingOptions = SAVING_DOMAINS;
-                Loading.start('importDomainFromDb');
-
-                $http.post('/api/v1/configuration/domains/save/batch', batch)
-                    .success(function(savedBatch) {
-                        let lastItem;
-                        const newItems = [];
-
-                        _.forEach(_mapCaches(savedBatch.generatedCaches), function(cache) {
-                            $scope.caches.push(cache);
-                        });
-
-                        _.forEach(savedBatch.savedDomains, function(savedItem) {
-                            const idx = _.findIndex($scope.domains, function(domain) {
-                                return domain._id === savedItem._id;
-                            });
-
-                            if (idx >= 0)
-                                $scope.domains[idx] = savedItem;
-                            else
-                                newItems.push(savedItem);
-
-                            lastItem = savedItem;
-                        });
-
-                        _.forEach(newItems, function(item) {
-                            $scope.domains.push(item);
-                        });
-
-                        if (!lastItem && $scope.domains.length > 0)
-                            lastItem = $scope.domains[0];
-
-                        $scope.selectItem(lastItem);
-
-                        Messages.showInfo('Domain models imported from database.');
-
-                        $scope.ui.activePanels = [0, 1, 2];
-
-                        $scope.ui.showValid = true;
-                    })
-                    .error(Messages.showError)
-                    .finally(() => {
-                        Loading.finish('importDomainFromDb');
-
-                        importDomainModal.hide();
-                    });
-            }
-            else
-                importDomainModal.hide();
-        }
-
-        function _saveDomainModel() {
-            if (LegacyUtils.isEmptyString($scope.ui.packageName))
-                return LegacyUtils.showPopoverMessage(null, null, 'domainPackageName', 'Package could not be empty');
-
-            if (!LegacyUtils.isValidJavaClass('Package', $scope.ui.packageName, false, 'domainPackageName', true))
-                return false;
-
-            const batch = [];
-            const tables = [];
-            const checkedCaches = [];
-
-            let dupCnt = 0;
-            let containKey = true;
-
-            function queryField(name, jdbcType) {
-                return {name: toJavaName(name), className: jdbcType.javaType};
-            }
-
-            function dbField(name, jdbcType, nullable) {
-                return {
-                    jdbcType,
-                    databaseFieldName: name,
-                    databaseFieldType: jdbcType.dbName,
-                    javaFieldName: toJavaName(name),
-                    javaFieldType: nullable ? jdbcType.javaType :
-                        ($scope.ui.usePrimitives && jdbcType.primitiveType ? jdbcType.primitiveType : jdbcType.javaType)
-                };
-            }
-
-            _.forEach($scope.importDomain.tables, function(table) {
-                if (table.use) {
-                    const qryFields = [];
-                    const indexes = [];
-                    const keyFields = [];
-                    const valFields = [];
-                    const aliases = [];
-
-                    const tableName = table.tbl;
-
-                    const dup = tables.indexOf(tableName) >= 0;
-
-                    if (dup)
-                        dupCnt++;
-
-                    const typeName = toJavaClassName(tableName);
-                    const valType = _toJavaPackage($scope.ui.packageName) + '.' + typeName;
-
-                    let _containKey = false;
-
-                    _.forEach(table.cols, function(col) {
-                        const colName = col.name;
-                        const jdbcType = LegacyUtils.findJdbcType(col.type);
-                        const nullable = col.nullable;
-
-                        qryFields.push(queryField(colName, jdbcType));
-
-                        const fld = dbField(colName, jdbcType, nullable);
-
-                        if ($scope.ui.generateAliases && !_.find(aliases, {field: fld.javaFieldName}) &&
-                            fld.javaFieldName.toUpperCase() !== fld.databaseFieldName.toUpperCase())
-                            aliases.push({field: fld.javaFieldName, alias: fld.databaseFieldName});
-
-                        if (col.key) {
-                            keyFields.push(fld);
-
-                            _containKey = true;
-                        }
-                        else
-                            valFields.push(fld);
-                    });
-
-                    containKey &= _containKey;
-
-                    if (table.idxs) {
-                        _.forEach(table.idxs, function(idx) {
-                            const fields = Object.keys(idx.fields);
-
-                            indexes.push({
-                                name: idx.name, indexType: 'SORTED', fields: _.map(fields, function(fieldName) {
-                                    return {
-                                        name: toJavaName(fieldName),
-                                        direction: idx.fields[fieldName]
-                                    };
-                                })
-                            });
-                        });
-                    }
-
-                    const domainFound = _.find($scope.domains, function(domain) {
-                        return domain.valueType === valType;
-                    });
-
-                    const newDomain = {
-                        confirm: false,
-                        skip: false,
-                        space: $scope.spaces[0],
-                        caches: []
-                    };
-
-                    if (LegacyUtils.isDefined(domainFound)) {
-                        newDomain._id = domainFound._id;
-                        newDomain.caches = domainFound.caches;
-                        newDomain.confirm = true;
-                    }
-
-                    const dupSfx = (dup ? '_' + dupCnt : '');
-
-                    newDomain.keyType = valType + 'Key' + dupSfx;
-                    newDomain.valueType = valType + dupSfx;
-                    newDomain.queryMetadata = 'Configuration';
-                    newDomain.databaseSchema = table.schema;
-                    newDomain.databaseTable = tableName;
-                    newDomain.fields = qryFields;
-                    newDomain.indexes = indexes;
-                    newDomain.keyFields = keyFields;
-                    newDomain.aliases = aliases;
-                    newDomain.valueFields = valFields;
-
-                    // If value fields not found - copy key fields.
-                    if (_.isEmpty(valFields))
-                        newDomain.valueFields = keyFields.slice();
-
-                    // Use Java built-in type for key.
-                    if ($scope.ui.builtinKeys && newDomain.keyFields.length === 1) {
-                        const keyField = newDomain.keyFields[0];
-
-                        newDomain.keyType = keyField.jdbcType.javaType;
-
-                        // Exclude key column from query fields and indexes.
-                        newDomain.fields = _.filter(newDomain.fields, function(field) {
-                            return field.name !== keyField.javaFieldName;
-                        });
-
-                        _.forEach(newDomain.indexes, function(index) {
-                            index.fields = _.filter(index.fields, function(field) {
-                                return field.name !== keyField.javaFieldName;
-                            });
-                        });
-
-                        newDomain.indexes = _.filter(newDomain.indexes, (index) => !_.isEmpty(index.fields));
-                    }
-
-                    // Prepare caches for generation.
-                    if (table.action === IMPORT_DM_NEW_CACHE) {
-                        const template = _.find(_importCachesOrTemplates, {value: table.cacheOrTemplate});
-
-                        const newCache = angular.copy(template.cache);
-
-                        newDomain.newCache = newCache;
-
-                        delete newCache._id;
-                        newCache.name = typeName + 'Cache';
-                        newCache.clusters = $scope.ui.generatedCachesClusters;
-
-                        // POJO store factory is not defined in template.
-                        if (!newCache.cacheStoreFactory || newCache.cacheStoreFactory.kind !== 'CacheJdbcPojoStoreFactory') {
-                            const dialect = $scope.importDomain.demo ? 'H2' : $scope.selectedPreset.db;
-
-                            newCache.cacheStoreFactory = {
-                                kind: 'CacheJdbcPojoStoreFactory',
-                                CacheJdbcPojoStoreFactory: {dataSourceBean: 'ds' + dialect, dialect},
-                                CacheJdbcBlobStoreFactory: { connectVia: 'DataSource' }
-                            };
-                        }
-
-                        if (!newCache.readThrough && !newCache.writeThrough) {
-                            newCache.readThrough = true;
-                            newCache.writeThrough = true;
-                        }
-                    }
-                    else {
-                        const cacheId = table.cacheOrTemplate;
-
-                        newDomain.caches = [cacheId];
-
-                        if (!_.includes(checkedCaches, cacheId)) {
-                            const cache = _.find($scope.caches, {value: cacheId}).cache;
-
-                            const change = LegacyUtils.autoCacheStoreConfiguration(cache, [newDomain]);
-
-                            if (change)
-                                newDomain.cacheStoreChanges = [{cacheId, change}];
-
-                            checkedCaches.push(cacheId);
-                        }
-                    }
-
-                    batch.push(newDomain);
-                    tables.push(tableName);
-                }
-            });
-
-            /**
-             * Generate message to show on confirm dialog.
-             *
-             * @param meta Object to confirm.
-             * @returns {string} Generated message.
-             */
-            function overwriteMessage(meta) {
-                return '<span>' +
-                    'Domain model with name &quot;' + meta.databaseTable + '&quot; already exist.<br/><br/>' +
-                    'Are you sure you want to overwrite it?' +
-                    '</span>';
-            }
-
-            const itemsToConfirm = _.filter(batch, (item) => item.confirm);
-
-            function checkOverwrite() {
-                if (itemsToConfirm.length > 0) {
-                    ConfirmBatch.confirm(overwriteMessage, itemsToConfirm)
-                        .then(() => _saveBatch(_.filter(batch, (item) => !item.skip)))
-                        .catch(() => Messages.showError('Importing of domain models interrupted by user.'));
-                }
-                else
-                    _saveBatch(batch);
-            }
-
-            if (containKey)
-                checkOverwrite();
-            else {
-                Confirm.confirm('Some tables have no primary key.<br/>' +
-                        'You will need to configure key type and key fields for such tables after import complete.')
-                    .then(() => checkOverwrite());
-            }
-        }
-
-        $scope.importDomainNext = function() {
-            if (!$scope.importDomainNextAvailable())
-                return;
-
-            const act = $scope.importDomain.action;
-
-            if (act === 'drivers' && $scope.importDomain.jdbcDriversNotFound)
-                importDomainModal.hide();
-            else if (act === 'connect')
-                _loadSchemas();
-            else if (act === 'schemas')
-                _loadTables();
-            else if (act === 'tables')
-                _selectOptions();
-            else if (act === 'options')
-                _saveDomainModel();
-        };
-
-        $scope.nextTooltipText = function() {
-            const importDomainNextAvailable = $scope.importDomainNextAvailable();
-
-            const act = $scope.importDomain.action;
-
-            if (act === 'drivers' && $scope.importDomain.jdbcDriversNotFound)
-                return 'Resolve issue with JDBC drivers<br>Close this dialog and try again';
-
-            if (act === 'connect' || act === 'drivers')
-                return 'Click to load list of schemas from database';
-
-            if (act === 'schemas')
-                return importDomainNextAvailable ? 'Click to load list of tables from database' : 'Select schemas to continue';
-
-            if (act === 'tables')
-                return importDomainNextAvailable ? 'Click to show import options' : 'Select tables to continue';
-
-            if (act === 'options')
-                return 'Click to import domain model for selected tables';
-
-            return 'Click to continue';
-        };
-
-        $scope.prevTooltipText = function() {
-            const act = $scope.importDomain.action;
-
-            if (act === 'schemas')
-                return $scope.importDomain.demo ? 'Click to return on demo description step' : 'Click to return on connection configuration step';
-
-            if (act === 'tables')
-                return 'Click to return on schemas selection step';
-
-            if (act === 'options')
-                return 'Click to return on tables selection step';
-        };
-
-        $scope.importDomainNextAvailable = function() {
-            let res = true;
-
-            switch ($scope.importDomain.action) {
-                case 'schemas':
-                    res = _.isEmpty($scope.importDomain.schemas) || _.find($scope.importDomain.schemas, {use: true});
-
-                    break;
-
-                case 'tables':
-                    res = _.find($scope.importDomain.tables, {use: true});
-
-                    break;
-
-                default:
-            }
-
-            return res;
-        };
-
-        $scope.importDomainPrev = function() {
-            $scope.importDomain.button = 'Next';
-
-            if ($scope.importDomain.action === 'options') {
-                $scope.importDomain.action = 'tables';
-                $scope.importDomain.info = INFO_SELECT_TABLES;
-            }
-            else if ($scope.importDomain.action === 'tables' && $scope.importDomain.schemas.length > 0) {
-                $scope.importDomain.action = 'schemas';
-                $scope.importDomain.info = INFO_SELECT_SCHEMAS;
-            }
-            else {
-                $scope.importDomain.action = 'connect';
-                $scope.importDomain.info = INFO_CONNECT_TO_DB;
-            }
-        };
-
-        $scope.domainModelTitle = function() {
-            return $scope.ui.showValid ? 'Domain model types:' : 'Domain model types without key fields:';
-        };
-
-        function selectFirstItem() {
-            if ($scope.domains.length > 0)
-                $scope.selectItem($scope.domains[0]);
-        }
-
-        $scope.importActions = [{
-            label: 'Create new cache by template',
-            shortLabel: 'Create',
-            value: IMPORT_DM_NEW_CACHE
-        }];
-
-        $scope.importCommon = {};
-
-        // When landing on the page, get domain models and show them.
-        Loading.start('loadingDomainModelsScreen');
-
-        $http.post('/api/v1/configuration/domains/list')
-            .success(function(data) {
-                $scope.spaces = data.spaces;
-                $scope.clusters = _.map(data.clusters, function(cluster) {
-                    return {
-                        value: cluster._id,
-                        label: cluster.name
-                    };
-                });
-                $scope.caches = _mapCaches(data.caches);
-                $scope.domains = data.domains;
-
-                _.forEach($scope.clusters, function(cluster) {
-                    $scope.ui.generatedCachesClusters.push(cluster.value);
-                });
-
-                if (!_.isEmpty($scope.caches)) {
-                    $scope.importActions.push({
-                        label: 'Associate with existing cache',
-                        shortLabel: 'Associate',
-                        value: IMPORT_DM_ASSOCIATE_CACHE
-                    });
-                }
-
-                $scope.$watch('importCommon.action', _fillCommonCachesOrTemplates($scope.importCommon), true);
-
-                $scope.importCommon.action = IMPORT_DM_NEW_CACHE;
-
-                if ($state.params.linkId)
-                    $scope.createItem($state.params.linkId);
-                else {
-                    const lastSelectedDomain = angular.fromJson(sessionStorage.lastSelectedDomain);
-
-                    if (lastSelectedDomain) {
-                        const idx = _.findIndex($scope.domains, function(domain) {
-                            return domain._id === lastSelectedDomain;
-                        });
-
-                        if (idx >= 0)
-                            $scope.selectItem($scope.domains[idx]);
-                        else {
-                            sessionStorage.removeItem('lastSelectedDomain');
-
-                            selectFirstItem();
-                        }
-                    }
-                    else
-                        selectFirstItem();
-                }
-
-                $scope.$watch('ui.inputForm.$valid', function(valid) {
-                    if (valid && ModelNormalizer.isEqual(__original_value, $scope.backupItem))
-                        $scope.ui.inputForm.$dirty = false;
-                });
-
-                $scope.$watch('backupItem', function(val) {
-                    const form = $scope.ui.inputForm;
-
-                    if (form.$pristine || (form.$valid && ModelNormalizer.isEqual(__original_value, val)))
-                        form.$setPristine();
-                    else
-                        form.$setDirty();
-                }, true);
-            })
-            .catch(Messages.showError)
-            .finally(() => {
-                $scope.ui.ready = true;
-                $scope.ui.inputForm.$setPristine();
-
-                Loading.finish('loadingDomainModelsScreen');
-            });
-
-        const clearFormDefaults = (ngFormCtrl) => {
-            ngFormCtrl.$defaults = {};
-
-            _.forOwn(ngFormCtrl, (value, key) => {
-                if (value && key !== '$$parentForm' && value.constructor.name === 'FormController')
-                    clearFormDefaults(value);
-            });
-        };
-
-        $scope.selectItem = function(item, backup) {
-            function selectItem() {
-                clearFormDefaults($scope.ui.inputForm);
-
-                LegacyTable.tableReset();
-
-                $scope.selectedItem = item;
-
-                try {
-                    if (item && item._id)
-                        sessionStorage.lastSelectedDomain = angular.toJson(item._id);
-                    else
-                        sessionStorage.removeItem('lastSelectedDomain');
-                }
-                catch (ignored) {
-                    // Ignore possible errors when read from storage.
-                }
-
-                if (backup)
-                    $scope.backupItem = backup;
-                else if (item)
-                    $scope.backupItem = angular.copy(item);
-                else
-                    $scope.backupItem = emptyDomain;
-
-                $scope.backupItem = angular.merge({}, blank, $scope.backupItem);
-
-                __original_value = ModelNormalizer.normalize($scope.backupItem);
-
-                if (LegacyUtils.isDefined($scope.backupItem) && !LegacyUtils.isDefined($scope.backupItem.queryMetadata))
-                    $scope.backupItem.queryMetadata = 'Configuration';
-
-                if (LegacyUtils.isDefined($scope.selectedItem) && !LegacyUtils.isDefined($scope.selectedItem.queryMetadata))
-                    $scope.selectedItem.queryMetadata = 'Configuration';
-
-                if (LegacyUtils.getQueryVariable('new'))
-                    $state.go('base.configuration.domains');
-            }
-
-            LegacyUtils.confirmUnsavedChanges($scope.ui.inputForm.$dirty, selectItem);
-        };
-
-        // Add new domain model.
-        $scope.createItem = function(cacheId) {
-            if ($scope.tableReset(true)) {
-                $timeout(() => {
-                    LegacyUtils.ensureActivePanel($scope.ui, 'query');
-                    LegacyUtils.ensureActivePanel($scope.ui, 'general', 'keyType');
-                });
-
-                $scope.selectItem(null, prepareNewItem(cacheId));
-            }
-        };
-
-        function checkQueryConfiguration(item) {
-            if (item.queryMetadata === 'Configuration' && LegacyUtils.domainForQueryConfigured(item)) {
-                if (_.isEmpty(item.fields))
-                    return showPopoverMessage($scope.ui, 'query', 'queryFields', 'Query fields should not be empty');
-
-                const indexes = item.indexes;
-
-                if (indexes && indexes.length > 0) {
-                    if (_.find(indexes, function(index, i) {
-                        if (_.isEmpty(index.fields))
-                            return !showPopoverMessage($scope.ui, 'query', 'indexes' + i, 'Index fields are not specified');
-                    }))
-                        return false;
-                }
-            }
-
-            return true;
-        }
-
-        function checkStoreConfiguration(item) {
-            if (LegacyUtils.domainForStoreConfigured(item)) {
-                if (LegacyUtils.isEmptyString(item.databaseSchema))
-                    return showPopoverMessage($scope.ui, 'store', 'databaseSchema', 'Database schema should not be empty');
-
-                if (LegacyUtils.isEmptyString(item.databaseTable))
-                    return showPopoverMessage($scope.ui, 'store', 'databaseTable', 'Database table should not be empty');
-
-                if (_.isEmpty(item.keyFields))
-                    return showPopoverMessage($scope.ui, 'store', 'keyFields', 'Key fields are not specified');
-
-                if (LegacyUtils.isJavaBuiltInClass(item.keyType) && item.keyFields.length !== 1)
-                    return showPopoverMessage($scope.ui, 'store', 'keyFields', 'Only one field should be specified in case when key type is a Java built-in type');
-
-                if (_.isEmpty(item.valueFields))
-                    return showPopoverMessage($scope.ui, 'store', 'valueFields', 'Value fields are not specified');
-            }
-
-            return true;
-        }
-
-        // Check domain model logical consistency.
-        function validate(item) {
-            if (!LegacyUtils.checkFieldValidators($scope.ui))
-                return false;
-
-            if (!checkQueryConfiguration(item))
-                return false;
-
-            if (!checkStoreConfiguration(item))
-                return false;
-
-            if (!LegacyUtils.domainForStoreConfigured(item) && !LegacyUtils.domainForQueryConfigured(item) && item.queryMetadata === 'Configuration')
-                return showPopoverMessage($scope.ui, 'query', 'query-title', 'SQL query domain model should be configured');
-
-            return true;
-        }
-
-        function _checkShowValidPresentation() {
-            if (!$scope.ui.showValid) {
-                const validFilter = $filter('domainsValidation');
-
-                $scope.ui.showValid = validFilter($scope.domains, false, true).length === 0;
-            }
-        }
-
-        // Save domain models into database.
-        function save(item) {
-            const qry = LegacyUtils.domainForQueryConfigured(item);
-            const str = LegacyUtils.domainForStoreConfigured(item);
-
-            item.kind = 'query';
-
-            if (qry && str)
-                item.kind = 'both';
-            else if (str)
-                item.kind = 'store';
-
-            $http.post('/api/v1/configuration/domains/save', item)
-                .success(function(res) {
-                    $scope.ui.inputForm.$setPristine();
-
-                    const savedMeta = res.savedDomains[0];
-
-                    const idx = _.findIndex($scope.domains, function(domain) {
-                        return domain._id === savedMeta._id;
-                    });
-
-                    if (idx >= 0)
-                        angular.extend($scope.domains[idx], savedMeta);
-                    else
-                        $scope.domains.push(savedMeta);
-
-                    _.forEach($scope.caches, (cache) => {
-                        if (_.includes(item.caches, cache.value))
-                            cache.cache.domains = _.union(cache.cache.domains, [savedMeta._id]);
-                        else
-                            _.remove(cache.cache.domains, (id) => id === savedMeta._id);
-                    });
-
-                    $scope.selectItem(savedMeta);
-
-                    Messages.showInfo('Domain model "' + item.valueType + '" saved.');
-
-                    _checkShowValidPresentation();
-                })
-                .error(Messages.showError);
-        }
-
-        // Save domain model.
-        $scope.saveItem = function() {
-            if ($scope.tableReset(true)) {
-                const item = $scope.backupItem;
-
-                item.cacheStoreChanges = [];
-
-                _.forEach(item.caches, function(cacheId) {
-                    const cache = _.find($scope.caches, {value: cacheId}).cache;
-
-                    const change = LegacyUtils.autoCacheStoreConfiguration(cache, [item]);
-
-                    if (change)
-                        item.cacheStoreChanges.push({cacheId, change});
-                });
-
-                if (validate(item))
-                    save(item);
-            }
-        };
-
-        function _domainNames() {
-            return _.map($scope.domains, function(domain) {
-                return domain.valueType;
-            });
-        }
-
-        function _newNameIsValidJavaClass(newName) {
-            return LegacyUtils.isValidJavaClass('New name for value type', newName, false, 'copy-new-name');
-        }
-
-        // Save domain model with new name.
-        $scope.cloneItem = function() {
-            if ($scope.tableReset(true) && validate($scope.backupItem)) {
-                Clone.confirm($scope.backupItem.valueType, _domainNames(), _newNameIsValidJavaClass).then(function(newName) {
-                    const item = angular.copy($scope.backupItem);
-
-                    delete item._id;
-                    item.valueType = newName;
-
-                    save(item);
-                });
-            }
-        };
-
-        // Remove domain model from db.
-        $scope.removeItem = function() {
-            LegacyTable.tableReset();
-
-            const selectedItem = $scope.selectedItem;
-
-            Confirm.confirm('Are you sure you want to remove domain model: "' + selectedItem.valueType + '"?')
-                .then(function() {
-                    const _id = selectedItem._id;
-
-                    $http.post('/api/v1/configuration/domains/remove', {_id})
-                        .success(function() {
-                            Messages.showInfo('Domain model has been removed: ' + selectedItem.valueType);
-
-                            const domains = $scope.domains;
-
-                            const idx = _.findIndex(domains, function(domain) {
-                                return domain._id === _id;
-                            });
-
-                            if (idx >= 0) {
-                                domains.splice(idx, 1);
-
-                                if (domains.length > 0)
-                                    $scope.selectItem(domains[0]);
-                                else {
-                                    $scope.backupItem = emptyDomain;
-                                    $scope.ui.inputForm.$setPristine();
-                                }
-
-                                _.forEach($scope.caches, (cache) => _.remove(cache.cache.domains, (id) => id === _id));
-                            }
-
-                            _checkShowValidPresentation();
-                        })
-                        .error(Messages.showError);
-                });
-        };
-
-        // Remove all domain models from db.
-        $scope.removeAllItems = function() {
-            LegacyTable.tableReset();
-
-            Confirm.confirm('Are you sure you want to remove all domain models?')
-                .then(function() {
-                    $http.post('/api/v1/configuration/domains/remove/all')
-                        .success(function() {
-                            Messages.showInfo('All domain models have been removed');
-
-                            $scope.domains = [];
-
-                            _.forEach($scope.caches, (cache) => cache.cache.domains = []);
-
-                            $scope.ui.inputForm.$setPristine();
-                            $scope.backupItem = emptyDomain;
-                            $scope.ui.showValid = true;
-                        })
-                        .error(Messages.showError);
-                });
-        };
-
-        $scope.toggleValid = function() {
-            $scope.ui.showValid = !$scope.ui.showValid;
-
-            const validFilter = $filter('domainsValidation');
-
-            let idx = -1;
-
-            if (LegacyUtils.isDefined($scope.selectedItem)) {
-                idx = _.findIndex(validFilter($scope.domains, $scope.ui.showValid, true), function(domain) {
-                    return domain._id === $scope.selectedItem._id;
-                });
-            }
-
-            if (idx === -1)
-                $scope.backupItem = emptyDomain;
-        };
-
-        const pairFields = {
-            fields: {
-                msg: 'Query field class',
-                id: 'QryField',
-                idPrefix: 'Key',
-                searchCol: 'name',
-                valueCol: 'key',
-                classValidation: true,
-                dupObjName: 'name'
-            },
-            aliases: {id: 'Alias', idPrefix: 'Value', searchCol: 'alias', valueCol: 'value', dupObjName: 'alias'}
-        };
-
-        $scope.tablePairValid = function(item, field, index) {
-            const pairField = pairFields[field.model];
-
-            const pairValue = LegacyTable.tablePairValue(field, index);
-
-            if (pairField) {
-                const model = item[field.model];
-
-                if (LegacyUtils.isDefined(model)) {
-                    const idx = _.findIndex(model, function(pair) {
-                        return pair[pairField.searchCol] === pairValue[pairField.valueCol];
-                    });
-
-                    // Found duplicate by key.
-                    if (idx >= 0 && idx !== index)
-                        return showPopoverMessage($scope.ui, 'query', LegacyTable.tableFieldId(index, pairField.idPrefix + pairField.id), 'Field with such ' + pairField.dupObjName + ' already exists!');
-                }
-
-                if (pairField.classValidation && !LegacyUtils.isValidJavaClass(pairField.msg, pairValue.value, true, LegacyTable.tableFieldId(index, 'Value' + pairField.id), false, $scope.ui, 'query'))
-                    return LegacyTable.tableFocusInvalidField(index, 'Value' + pairField.id);
-            }
-
-            return true;
-        };
-
-        function tableDbFieldValue(field, index) {
-            return (index < 0) ? {
-                databaseFieldName: field.newDatabaseFieldName,
-                databaseFieldType: field.newDatabaseFieldType,
-                javaFieldName: field.newJavaFieldName,
-                javaFieldType: field.newJavaFieldType
-            } : {
-                databaseFieldName: field.curDatabaseFieldName,
-                databaseFieldType: field.curDatabaseFieldType,
-                javaFieldName: field.curJavaFieldName,
-                javaFieldType: field.curJavaFieldType
-            };
-        }
-
-        $scope.tableDbFieldSaveVisible = function(field, index) {
-            const dbFieldValue = tableDbFieldValue(field, index);
-
-            return LegacyUtils.isDefined(dbFieldValue.databaseFieldType) &&
-                LegacyUtils.isDefined(dbFieldValue.javaFieldType) &&
-                !LegacyUtils.isEmptyString(dbFieldValue.databaseFieldName) &&
-                !LegacyUtils.isEmptyString(dbFieldValue.javaFieldName);
-        };
-
-        const dbFieldTables = {
-            keyFields: {msg: 'Key field', id: 'KeyField'},
-            valueFields: {msg: 'Value field', id: 'ValueField'}
-        };
-
-        $scope.tableDbFieldSave = function(field, index, stopEdit) {
-            const dbFieldTable = dbFieldTables[field.model];
-
-            if (dbFieldTable) {
-                const dbFieldValue = tableDbFieldValue(field, index);
-
-                const item = $scope.backupItem;
-
-                let model = item[field.model];
-
-                if (!LegacyUtils.isValidJavaIdentifier(dbFieldTable.msg + ' java name', dbFieldValue.javaFieldName, LegacyTable.tableFieldId(index, 'JavaFieldName' + dbFieldTable.id)))
-                    return false;
-
-                if (LegacyUtils.isDefined(model)) {
-                    let idx = _.findIndex(model, function(dbMeta) {
-                        return dbMeta.databaseFieldName === dbFieldValue.databaseFieldName;
-                    });
-
-                    // Found duplicate.
-                    if (idx >= 0 && index !== idx)
-                        return showPopoverMessage($scope.ui, 'store', LegacyTable.tableFieldId(index, 'DatabaseFieldName' + dbFieldTable.id), 'Field with such database name already exists!');
-
-                    idx = _.findIndex(model, function(dbMeta) {
-                        return dbMeta.javaFieldName === dbFieldValue.javaFieldName;
-                    });
-
-                    // Found duplicate.
-                    if (idx >= 0 && index !== idx)
-                        return showPopoverMessage($scope.ui, 'store', LegacyTable.tableFieldId(index, 'JavaFieldName' + dbFieldTable.id), 'Field with such java name already exists!');
-
-                    if (index < 0)
-                        model.push(dbFieldValue);
-                    else {
-                        const dbField = model[index];
-
-                        dbField.databaseFieldName = dbFieldValue.databaseFieldName;
-                        dbField.databaseFieldType = dbFieldValue.databaseFieldType;
-                        dbField.javaFieldName = dbFieldValue.javaFieldName;
-                        dbField.javaFieldType = dbFieldValue.javaFieldType;
-                    }
-                }
-                else {
-                    model = [dbFieldValue];
-
-                    item[field.model] = model;
-                }
-
-                if (!stopEdit) {
-                    if (index < 0)
-                        LegacyTable.tableNewItem(field);
-                    else if (index < model.length - 1)
-                        LegacyTable.tableStartEdit(item, field, index + 1);
-                    else
-                        LegacyTable.tableNewItem(field);
-                }
-
-                return true;
-            }
-
-            return false;
-        };
-
-        function tableIndexName(field, index) {
-            return index < 0 ? field.newIndexName : field.curIndexName;
-        }
-
-        function tableIndexType(field, index) {
-            return index < 0 ? field.newIndexType : field.curIndexType;
-        }
-
-        $scope.tableIndexSaveVisible = function(field, index) {
-            return !LegacyUtils.isEmptyString(tableIndexName(field, index)) && LegacyUtils.isDefined(tableIndexType(field, index));
-        };
-
-        $scope.tableIndexSave = function(field, curIdx, stopEdit) {
-            const indexName = tableIndexName(field, curIdx);
-            const indexType = tableIndexType(field, curIdx);
-
-            const item = $scope.backupItem;
-
-            const indexes = item.indexes;
-
-            if (LegacyUtils.isDefined(indexes)) {
-                const idx = _.findIndex(indexes, function(index) {
-                    return index.name === indexName;
-                });
-
-                // Found duplicate.
-                if (idx >= 0 && idx !== curIdx)
-                    return showPopoverMessage($scope.ui, 'query', LegacyTable.tableFieldId(curIdx, 'IndexName'), 'Index with such name already exists!');
-            }
-
-            LegacyTable.tableReset();
-
-            if (curIdx < 0) {
-                const newIndex = {name: indexName, indexType};
-
-                if (item.indexes)
-                    item.indexes.push(newIndex);
-                else
-                    item.indexes = [newIndex];
-            }
-            else {
-                item.indexes[curIdx].name = indexName;
-                item.indexes[curIdx].indexType = indexType;
-            }
-
-            if (!stopEdit) {
-                if (curIdx < 0)
-                    $scope.tableIndexNewItem(field, item.indexes.length - 1);
-                else {
-                    const index = item.indexes[curIdx];
-
-                    if (index.fields && index.fields.length > 0)
-                        $scope.tableIndexItemStartEdit(field, curIdx, 0);
-                    else
-                        $scope.tableIndexNewItem(field, curIdx);
-                }
-            }
-
-            return true;
-        };
-
-        $scope.tableIndexNewItem = function(field, indexIdx) {
-            if ($scope.tableReset(true)) {
-                const index = $scope.backupItem.indexes[indexIdx];
-
-                LegacyTable.tableState(field, -1, 'table-index-fields');
-                LegacyTable.tableFocusInvalidField(-1, 'FieldName' + (index.indexType === 'SORTED' ? 'S' : '') + indexIdx);
-
-                field.newFieldName = null;
-                field.newDirection = true;
-                field.indexIdx = indexIdx;
-            }
-        };
-
-        $scope.tableIndexNewItemActive = function(field, itemIndex) {
-            const indexes = $scope.backupItem.indexes;
-
-            if (indexes) {
-                const index = indexes[itemIndex];
-
-                if (index)
-                    return LegacyTable.tableNewItemActive({model: 'table-index-fields'}) && field.indexIdx === itemIndex;
-            }
-
-            return false;
-        };
-
-        $scope.tableIndexItemEditing = function(field, itemIndex, curIdx) {
-            const indexes = $scope.backupItem.indexes;
-
-            if (indexes) {
-                const index = indexes[itemIndex];
-
-                if (index)
-                    return LegacyTable.tableEditing({model: 'table-index-fields'}, curIdx) && field.indexIdx === itemIndex;
-            }
-
-            return false;
-        };
-
-        function tableIndexItemValue(field, index) {
-            return index < 0 ? {
-                name: field.newFieldName,
-                direction: field.newDirection
-            } : {
-                name: field.curFieldName,
-                direction: field.curDirection
-            };
-        }
-
-        $scope.tableIndexItemStartEdit = function(field, indexIdx, curIdx) {
-            if ($scope.tableReset(true)) {
-                const index = $scope.backupItem.indexes[indexIdx];
-
-                LegacyTable.tableState(field, curIdx, 'table-index-fields');
-
-                const indexItem = index.fields[curIdx];
-
-                field.curFieldName = indexItem.name;
-                field.curDirection = indexItem.direction;
-                field.indexIdx = indexIdx;
-
-                Focus.move('curFieldName' + (index.indexType === 'SORTED' ? 'S' : '') + field.indexIdx + '-' + curIdx);
-            }
-        };
-
-        $scope.tableIndexItemSaveVisible = function(field, index) {
-            return !LegacyUtils.isEmptyString(tableIndexItemValue(field, index).name);
-        };
-
-        $scope.tableIndexItemSave = function(field, indexIdx, curIdx, stopEdit) {
-            const indexItemValue = tableIndexItemValue(field, curIdx);
-
-            const index = $scope.backupItem.indexes[indexIdx];
-
-            const fields = index.fields;
-
-            if (LegacyUtils.isDefined(fields)) {
-                const idx = _.findIndex(fields, (fld) => fld.name === indexItemValue.name);
-
-                // Found duplicate.
-                if (idx >= 0 && idx !== curIdx)
-                    return showPopoverMessage($scope.ui, 'query', LegacyTable.tableFieldId(curIdx, 'FieldName' + (index.indexType === 'SORTED' ? 'S' : '') + indexIdx + (curIdx >= 0 ? '-' : '')), 'Field with such name already exists in index!');
-            }
-
-            LegacyTable.tableReset();
-
-            field.indexIdx = -1;
-
-            if (curIdx < 0) {
-                if (index.fields)
-                    index.fields.push(indexItemValue);
-                else
-                    index.fields = [indexItemValue];
-
-                if (!stopEdit)
-                    $scope.tableIndexNewItem(field, indexIdx);
-            }
-            else {
-                index.fields[curIdx] = indexItemValue;
-
-                if (!stopEdit) {
-                    if (curIdx < index.fields.length - 1)
-                        $scope.tableIndexItemStartEdit(field, indexIdx, curIdx + 1);
-                    else
-                        $scope.tableIndexNewItem(field, indexIdx);
-                }
-            }
-
-            return true;
-        };
-
-        $scope.tableRemoveIndexItem = function(index, curIdx) {
-            LegacyTable.tableReset();
-
-            index.fields.splice(curIdx, 1);
-        };
-
-        $scope.resetAll = function() {
-            LegacyTable.tableReset();
-
-            Confirm.confirm('Are you sure you want to undo all changes for current domain model?')
-                .then(function() {
-                    $scope.backupItem = $scope.selectedItem ? angular.copy($scope.selectedItem) : prepareNewItem();
-                    $scope.ui.inputForm.$setPristine();
-                });
-        };
-    }
-]];

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/src/main/js/controllers/igfs-controller.js
----------------------------------------------------------------------
diff --git a/modules/web-console/src/main/js/controllers/igfs-controller.js b/modules/web-console/src/main/js/controllers/igfs-controller.js
deleted file mode 100644
index 5f5f0bb..0000000
--- a/modules/web-console/src/main/js/controllers/igfs-controller.js
+++ /dev/null
@@ -1,401 +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.
- */
-
-// Controller for IGFS screen.
-export default ['igfsController', [
-    '$scope', '$http', '$state', '$filter', '$timeout', 'IgniteLegacyUtils', 'IgniteMessages', 'IgniteConfirm', 'IgniteClone', 'IgniteLoading', 'IgniteModelNormalizer', 'IgniteUnsavedChangesGuard', 'IgniteLegacyTable',
-    function($scope, $http, $state, $filter, $timeout, LegacyUtils, Messages, Confirm, Clone, Loading, ModelNormalizer, UnsavedChangesGuard, LegacyTable) {
-        UnsavedChangesGuard.install($scope);
-
-        const emptyIgfs = {empty: true};
-
-        let __original_value;
-
-        const blank = {
-            ipcEndpointConfiguration: {},
-            secondaryFileSystem: {}
-        };
-
-        // We need to initialize backupItem with empty object in order to properly used from angular directives.
-        $scope.backupItem = emptyIgfs;
-
-        $scope.ui = LegacyUtils.formUI();
-        $scope.ui.activePanels = [0];
-        $scope.ui.topPanels = [0];
-
-        $scope.compactJavaName = LegacyUtils.compactJavaName;
-        $scope.widthIsSufficient = LegacyUtils.widthIsSufficient;
-        $scope.saveBtnTipText = LegacyUtils.saveBtnTipText;
-
-        const showPopoverMessage = LegacyUtils.showPopoverMessage;
-
-        $scope.tableSave = function(field, index, stopEdit) {
-            if (field.type === 'pathModes' && LegacyTable.tablePairSaveVisible(field, index))
-                return LegacyTable.tablePairSave($scope.tablePairValid, $scope.backupItem, field, index, stopEdit);
-
-            return true;
-        };
-
-        $scope.tableReset = (trySave) => {
-            const field = LegacyTable.tableField();
-
-            if (trySave && LegacyUtils.isDefined(field) && !$scope.tableSave(field, LegacyTable.tableEditedRowIndex(), true))
-                return false;
-
-            LegacyTable.tableReset();
-
-            return true;
-        };
-
-        $scope.tableNewItem = function(field) {
-            if ($scope.tableReset(true))
-                LegacyTable.tableNewItem(field);
-        };
-
-        $scope.tableNewItemActive = LegacyTable.tableNewItemActive;
-
-        $scope.tableStartEdit = function(item, field, index) {
-            if ($scope.tableReset(true))
-                LegacyTable.tableStartEdit(item, field, index, $scope.tableSave);
-        };
-
-        $scope.tableEditing = LegacyTable.tableEditing;
-        $scope.tablePairSave = LegacyTable.tablePairSave;
-        $scope.tablePairSaveVisible = LegacyTable.tablePairSaveVisible;
-
-        $scope.tableRemove = function(item, field, index) {
-            if ($scope.tableReset(true))
-                LegacyTable.tableRemove(item, field, index);
-        };
-
-        $scope.tablePairValid = function(item, field, index) {
-            const pairValue = LegacyTable.tablePairValue(field, index);
-
-            const model = item[field.model];
-
-            if (LegacyUtils.isDefined(model)) {
-                const idx = _.findIndex(model, function(pair) {
-                    return pair.path === pairValue.key;
-                });
-
-                // Found duplicate.
-                if (idx >= 0 && idx !== index)
-                    return showPopoverMessage($scope.ui, 'misc', LegacyTable.tableFieldId(index, 'KeyPathMode'), 'Such path already exists!');
-            }
-
-            return true;
-        };
-
-        $scope.tblPathModes = {
-            type: 'pathModes',
-            model: 'pathModes',
-            focusId: 'PathMode',
-            ui: 'table-pair',
-            keyName: 'path',
-            valueName: 'mode',
-            save: $scope.tableSave
-        };
-
-        $scope.igfsModes = LegacyUtils.mkOptions(['PRIMARY', 'PROXY', 'DUAL_SYNC', 'DUAL_ASYNC']);
-
-        $scope.contentVisible = function() {
-            const item = $scope.backupItem;
-
-            return !item.empty && (!item._id || _.find($scope.displayedRows, {_id: item._id}));
-        };
-
-        $scope.toggleExpanded = function() {
-            $scope.ui.expanded = !$scope.ui.expanded;
-
-            LegacyUtils.hidePopover();
-        };
-
-        $scope.igfss = [];
-        $scope.clusters = [];
-
-        function selectFirstItem() {
-            if ($scope.igfss.length > 0)
-                $scope.selectItem($scope.igfss[0]);
-        }
-
-        Loading.start('loadingIgfsScreen');
-
-        // When landing on the page, get IGFSs and show them.
-        $http.post('/api/v1/configuration/igfs/list')
-            .success(function(data) {
-                $scope.spaces = data.spaces;
-
-                $scope.igfss = data.igfss || [];
-
-                // For backward compatibility set colocateMetadata and relaxedConsistency default values.
-                _.forEach($scope.igfss, (igfs) => {
-                    if (_.isUndefined(igfs.colocateMetadata))
-                        igfs.colocateMetadata = true;
-
-                    if (_.isUndefined(igfs.relaxedConsistency))
-                        igfs.relaxedConsistency = true;
-                });
-
-                $scope.clusters = _.map(data.clusters || [], function(cluster) {
-                    return {
-                        value: cluster._id,
-                        label: cluster.name
-                    };
-                });
-
-                if ($state.params.linkId)
-                    $scope.createItem($state.params.linkId);
-                else {
-                    const lastSelectedIgfs = angular.fromJson(sessionStorage.lastSelectedIgfs);
-
-                    if (lastSelectedIgfs) {
-                        const idx = _.findIndex($scope.igfss, function(igfs) {
-                            return igfs._id === lastSelectedIgfs;
-                        });
-
-                        if (idx >= 0)
-                            $scope.selectItem($scope.igfss[idx]);
-                        else {
-                            sessionStorage.removeItem('lastSelectedIgfs');
-
-                            selectFirstItem();
-                        }
-                    }
-                    else
-                        selectFirstItem();
-                }
-
-                $scope.$watch('ui.inputForm.$valid', function(valid) {
-                    if (valid && ModelNormalizer.isEqual(__original_value, $scope.backupItem))
-                        $scope.ui.inputForm.$dirty = false;
-                });
-
-                $scope.$watch('backupItem', function(val) {
-                    const form = $scope.ui.inputForm;
-
-                    if (form.$pristine || (form.$valid && ModelNormalizer.isEqual(__original_value, val)))
-                        form.$setPristine();
-                    else
-                        form.$setDirty();
-                }, true);
-            })
-            .catch(Messages.showError)
-            .finally(function() {
-                $scope.ui.ready = true;
-                $scope.ui.inputForm.$setPristine();
-                Loading.finish('loadingIgfsScreen');
-            });
-
-        $scope.selectItem = function(item, backup) {
-            function selectItem() {
-                LegacyTable.tableReset();
-
-                $scope.selectedItem = item;
-
-                try {
-                    if (item && item._id)
-                        sessionStorage.lastSelectedIgfs = angular.toJson(item._id);
-                    else
-                        sessionStorage.removeItem('lastSelectedIgfs');
-                }
-                catch (ignored) {
-                    // No-op.
-                }
-
-                if (backup)
-                    $scope.backupItem = backup;
-                else if (item)
-                    $scope.backupItem = angular.copy(item);
-                else
-                    $scope.backupItem = emptyIgfs;
-
-                $scope.backupItem = angular.merge({}, blank, $scope.backupItem);
-
-                __original_value = ModelNormalizer.normalize($scope.backupItem);
-
-                if (LegacyUtils.getQueryVariable('new'))
-                    $state.go('base.configuration.igfs');
-            }
-
-            LegacyUtils.confirmUnsavedChanges($scope.backupItem && $scope.ui.inputForm.$dirty, selectItem);
-        };
-
-        $scope.linkId = () => $scope.backupItem._id ? $scope.backupItem._id : 'create';
-
-        function prepareNewItem(linkId) {
-            return {
-                space: $scope.spaces[0]._id,
-                ipcEndpointEnabled: true,
-                fragmentizerEnabled: true,
-                colocateMetadata: true,
-                relaxedConsistency: true,
-                clusters: linkId && _.find($scope.clusters, {value: linkId}) ? [linkId] :
-                    (_.isEmpty($scope.clusters) ? [] : [$scope.clusters[0].value])
-            };
-        }
-
-        // Add new IGFS.
-        $scope.createItem = function(linkId) {
-            if ($scope.tableReset(true)) {
-                $timeout(() => LegacyUtils.ensureActivePanel($scope.ui, 'general', 'igfsName'));
-
-                $scope.selectItem(null, prepareNewItem(linkId));
-            }
-        };
-
-        // Check IGFS logical consistency.
-        function validate(item) {
-            LegacyUtils.hidePopover();
-
-            if (LegacyUtils.isEmptyString(item.name))
-                return showPopoverMessage($scope.ui, 'general', 'igfsName', 'IGFS name should not be empty!');
-
-            if (!LegacyUtils.checkFieldValidators($scope.ui))
-                return false;
-
-            if (!item.secondaryFileSystemEnabled && (item.defaultMode === 'PROXY'))
-                return showPopoverMessage($scope.ui, 'secondaryFileSystem', 'secondaryFileSystem-title', 'Secondary file system should be configured for "PROXY" IGFS mode!');
-
-            if (item.pathModes) {
-                for (let pathIx = 0; pathIx < item.pathModes.length; pathIx++) {
-                    if (!item.secondaryFileSystemEnabled && item.pathModes[pathIx].mode === 'PROXY')
-                        return showPopoverMessage($scope.ui, 'secondaryFileSystem', 'secondaryFileSystem-title', 'Secondary file system should be configured for "PROXY" path mode!');
-                }
-            }
-
-            return true;
-        }
-
-        // Save IGFS in database.
-        function save(item) {
-            $http.post('/api/v1/configuration/igfs/save', item)
-                .success(function(_id) {
-                    $scope.ui.inputForm.$setPristine();
-
-                    const idx = _.findIndex($scope.igfss, function(igfs) {
-                        return igfs._id === _id;
-                    });
-
-                    if (idx >= 0)
-                        angular.merge($scope.igfss[idx], item);
-                    else {
-                        item._id = _id;
-                        $scope.igfss.push(item);
-                    }
-
-                    $scope.selectItem(item);
-
-                    Messages.showInfo('IGFS "' + item.name + '" saved.');
-                })
-                .error(Messages.showError);
-        }
-
-        // Save IGFS.
-        $scope.saveItem = function() {
-            if ($scope.tableReset(true)) {
-                const item = $scope.backupItem;
-
-                if (validate(item))
-                    save(item);
-            }
-        };
-
-        function _igfsNames() {
-            return _.map($scope.igfss, function(igfs) {
-                return igfs.name;
-            });
-        }
-
-        // Clone IGFS with new name.
-        $scope.cloneItem = function() {
-            if ($scope.tableReset(true) && validate($scope.backupItem)) {
-                Clone.confirm($scope.backupItem.name, _igfsNames()).then(function(newName) {
-                    const item = angular.copy($scope.backupItem);
-
-                    delete item._id;
-
-                    item.name = newName;
-
-                    save(item);
-                });
-            }
-        };
-
-        // Remove IGFS from db.
-        $scope.removeItem = function() {
-            LegacyTable.tableReset();
-
-            const selectedItem = $scope.selectedItem;
-
-            Confirm.confirm('Are you sure you want to remove IGFS: "' + selectedItem.name + '"?')
-                .then(function() {
-                    const _id = selectedItem._id;
-
-                    $http.post('/api/v1/configuration/igfs/remove', {_id})
-                        .success(function() {
-                            Messages.showInfo('IGFS has been removed: ' + selectedItem.name);
-
-                            const igfss = $scope.igfss;
-
-                            const idx = _.findIndex(igfss, function(igfs) {
-                                return igfs._id === _id;
-                            });
-
-                            if (idx >= 0) {
-                                igfss.splice(idx, 1);
-
-                                if (igfss.length > 0)
-                                    $scope.selectItem(igfss[0]);
-                                else {
-                                    $scope.backupItem = emptyIgfs;
-                                    $scope.ui.inputForm.$setPristine();
-                                }
-                            }
-                        })
-                        .error(Messages.showError);
-                });
-        };
-
-        // Remove all IGFS from db.
-        $scope.removeAllItems = function() {
-            LegacyTable.tableReset();
-
-            Confirm.confirm('Are you sure you want to remove all IGFS?')
-                .then(function() {
-                    $http.post('/api/v1/configuration/igfs/remove/all')
-                        .success(function() {
-                            Messages.showInfo('All IGFS have been removed');
-
-                            $scope.igfss = [];
-                            $scope.backupItem = emptyIgfs;
-                            $scope.ui.inputForm.$setPristine();
-                        })
-                        .error(Messages.showError);
-                });
-        };
-
-        $scope.resetAll = function() {
-            LegacyTable.tableReset();
-
-            Confirm.confirm('Are you sure you want to undo all changes for current IGFS?')
-                .then(function() {
-                    $scope.backupItem = $scope.selectedItem ? angular.copy($scope.selectedItem) : prepareNewItem();
-                    $scope.ui.inputForm.$setPristine();
-                });
-        };
-    }
-]];

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/src/main/js/controllers/profile-controller.js
----------------------------------------------------------------------
diff --git a/modules/web-console/src/main/js/controllers/profile-controller.js b/modules/web-console/src/main/js/controllers/profile-controller.js
deleted file mode 100644
index 6b8f541..0000000
--- a/modules/web-console/src/main/js/controllers/profile-controller.js
+++ /dev/null
@@ -1,91 +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.
- */
-
-// Controller for Profile screen.
-export default ['profileController', [
-    '$rootScope', '$scope', '$http', 'IgniteLegacyUtils', 'IgniteMessages', 'IgniteFocus', 'IgniteConfirm', 'IgniteCountries', 'User',
-    function($root, $scope, $http, LegacyUtils, Messages, Focus, Confirm, Countries, User) {
-        $scope.user = angular.copy($root.user);
-
-        $scope.countries = Countries.getAll();
-
-        $scope.generateToken = () => {
-            Confirm.confirm('Are you sure you want to change security token?')
-                .then(() => $scope.user.token = LegacyUtils.randomString(20));
-        };
-
-        const _passwordValid = () => {
-            const cur = $scope.user;
-
-            return !$scope.expandedPassword || (cur.password && cur.confirm && cur.password === cur.confirm);
-        };
-
-        const _profileChanged = () => {
-            const old = $root.user;
-            const cur = $scope.user;
-
-            return !_.isEqual(old, cur);
-        };
-
-        $scope.toggleToken = () => {
-            $scope.expandedToken = !$scope.expandedToken;
-
-            if (!$scope.expandedToken)
-                $scope.user.token = $root.user.token;
-        };
-
-        $scope.togglePassword = () => {
-            $scope.expandedPassword = !$scope.expandedPassword;
-
-            if ($scope.expandedPassword)
-                Focus.move('profile_password');
-            else {
-                delete $scope.user.password;
-                delete $scope.user.confirm;
-            }
-        };
-
-        $scope.profileCouldBeSaved = () => _profileChanged() && $scope.profileForm && $scope.profileForm.$valid && _passwordValid();
-
-        $scope.saveBtnTipText = () => {
-            if (!_profileChanged())
-                return 'Nothing to save';
-
-            if (!_passwordValid())
-                return 'Invalid password';
-
-            return $scope.profileForm && $scope.profileForm.$valid ? 'Save profile' : 'Invalid profile settings';
-        };
-
-        $scope.saveUser = () => {
-            $http.post('/api/v1/profile/save', $scope.user)
-                .then(User.read)
-                .then(() => {
-                    if ($scope.expandedPassword)
-                        $scope.togglePassword();
-
-                    if ($scope.expandedToken)
-                        $scope.toggleToken();
-
-                    Messages.showInfo('Profile saved.');
-
-                    Focus.move('profile-username');
-                })
-                .catch(({data}) => Messages.showError(Messages.errorMessage('Failed to save profile: ', data)));
-        };
-    }
-]];


[46/52] ignite git commit: Web Console beta-3.

Posted by ak...@apache.org.
http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-agent/demo/db-init.sql
----------------------------------------------------------------------
diff --git a/modules/web-agent/demo/db-init.sql b/modules/web-agent/demo/db-init.sql
deleted file mode 100644
index 0688ea0..0000000
--- a/modules/web-agent/demo/db-init.sql
+++ /dev/null
@@ -1,102 +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.
---
-
-CREATE TABLE COUNTRY (
-    ID         INTEGER NOT NULL PRIMARY KEY,
-    NAME       VARCHAR(50),
-    POPULATION INTEGER NOT NULL
-);
-
-CREATE TABLE DEPARTMENT (
-    ID         INTEGER NOT NULL PRIMARY KEY,
-    COUNTRY_ID INTEGER NOT NULL,
-    NAME       VARCHAR(50) NOT NULL
-);
-
-CREATE TABLE EMPLOYEE (
-    ID            INTEGER NOT NULL PRIMARY KEY,
-    DEPARTMENT_ID INTEGER NOT NULL,
-    MANAGER_ID    INTEGER,
-    FIRST_NAME    VARCHAR(50) NOT NULL,
-    LAST_NAME     VARCHAR(50) NOT NULL,
-    EMAIL         VARCHAR(50) NOT NULL,
-    PHONE_NUMBER  VARCHAR(50),
-    HIRE_DATE     DATE        NOT NULL,
-    JOB           VARCHAR(50) NOT NULL,
-    SALARY        DOUBLE
-);
-
-CREATE INDEX EMP_SALARY ON EMPLOYEE (SALARY ASC);
-CREATE INDEX EMP_NAMES ON EMPLOYEE (FIRST_NAME ASC, LAST_NAME ASC);
-
-CREATE SCHEMA CARS;
-
-CREATE TABLE CARS.PARKING (
-    ID       INTEGER     NOT NULL PRIMARY KEY,
-    NAME     VARCHAR(50) NOT NULL,
-    CAPACITY INTEGER NOT NULL
-);
-
-CREATE TABLE CARS.CAR (
-    ID         INTEGER NOT NULL PRIMARY KEY,
-    PARKING_ID INTEGER NOT NULL,
-    NAME       VARCHAR(50) NOT NULL
-);
-
-INSERT INTO COUNTRY(ID, NAME, POPULATION) VALUES(0, 'Country #1', 10000000);
-INSERT INTO COUNTRY(ID, NAME, POPULATION) VALUES(1, 'Country #2', 20000000);
-INSERT INTO COUNTRY(ID, NAME, POPULATION) VALUES(2, 'Country #3', 30000000);
-
-INSERT INTO DEPARTMENT(ID, COUNTRY_ID, NAME) VALUES(0, 0, 'Department #1');
-INSERT INTO DEPARTMENT(ID, COUNTRY_ID, NAME) VALUES(1, 0, 'Department #2');
-INSERT INTO DEPARTMENT(ID, COUNTRY_ID, NAME) VALUES(2, 2, 'Department #3');
-INSERT INTO DEPARTMENT(ID, COUNTRY_ID, NAME) VALUES(3, 1, 'Department #4');
-INSERT INTO DEPARTMENT(ID, COUNTRY_ID, NAME) VALUES(4, 1, 'Department #5');
-INSERT INTO DEPARTMENT(ID, COUNTRY_ID, NAME) VALUES(5, 1, 'Department #6');
-
-INSERT INTO EMPLOYEE(ID, DEPARTMENT_ID, FIRST_NAME, LAST_NAME, EMAIL, PHONE_NUMBER, HIRE_DATE, JOB, SALARY) VALUES(0, 0, 'First name manager #1', 'Last name manager #1', 'Email manager #1', 'Phone number manager #1', '2014-01-01', 'Job manager #1', 1100.00);
-INSERT INTO EMPLOYEE(ID, DEPARTMENT_ID, FIRST_NAME, LAST_NAME, EMAIL, PHONE_NUMBER, HIRE_DATE, JOB, SALARY) VALUES(1, 1, 'First name manager #2', 'Last name manager #2', 'Email manager #2', 'Phone number manager #2', '2014-01-01', 'Job manager #2', 2100.00);
-INSERT INTO EMPLOYEE(ID, DEPARTMENT_ID, FIRST_NAME, LAST_NAME, EMAIL, PHONE_NUMBER, HIRE_DATE, JOB, SALARY) VALUES(2, 2, 'First name manager #3', 'Last name manager #3', 'Email manager #3', 'Phone number manager #3', '2014-01-01', 'Job manager #3', 3100.00);
-INSERT INTO EMPLOYEE(ID, DEPARTMENT_ID, FIRST_NAME, LAST_NAME, EMAIL, PHONE_NUMBER, HIRE_DATE, JOB, SALARY) VALUES(3, 3, 'First name manager #4', 'Last name manager #4', 'Email manager #4', 'Phone number manager #4', '2014-01-01', 'Job manager #4', 1500.00);
-INSERT INTO EMPLOYEE(ID, DEPARTMENT_ID, FIRST_NAME, LAST_NAME, EMAIL, PHONE_NUMBER, HIRE_DATE, JOB, SALARY) VALUES(4, 4, 'First name manager #5', 'Last name manager #5', 'Email manager #5', 'Phone number manager #5', '2014-01-01', 'Job manager #5', 1700.00);
-INSERT INTO EMPLOYEE(ID, DEPARTMENT_ID, FIRST_NAME, LAST_NAME, EMAIL, PHONE_NUMBER, HIRE_DATE, JOB, SALARY) VALUES(5, 5, 'First name manager #6', 'Last name manager #6', 'Email manager #6', 'Phone number manager #6', '2014-01-01', 'Job manager #6', 1300.00);
-
-INSERT INTO EMPLOYEE(ID, DEPARTMENT_ID, MANAGER_ID, FIRST_NAME, LAST_NAME, EMAIL, PHONE_NUMBER, HIRE_DATE, JOB, SALARY) VALUES(101, 0, 0, 'First name employee #1', 'Last name employee #1', 'Email employee #1', 'Phone number employee #1', '2014-01-01', 'Job employee #1', 600.00);
-INSERT INTO EMPLOYEE(ID, DEPARTMENT_ID, MANAGER_ID, FIRST_NAME, LAST_NAME, EMAIL, PHONE_NUMBER, HIRE_DATE, JOB, SALARY) VALUES(102, 0, 0, 'First name employee #2', 'Last name employee #2', 'Email employee #2', 'Phone number employee #2', '2014-01-01', 'Job employee #2', 1600.00);
-INSERT INTO EMPLOYEE(ID, DEPARTMENT_ID, MANAGER_ID, FIRST_NAME, LAST_NAME, EMAIL, PHONE_NUMBER, HIRE_DATE, JOB, SALARY) VALUES(103, 1, 1, 'First name employee #3', 'Last name employee #3', 'Email employee #3', 'Phone number employee #3', '2014-01-01', 'Job employee #3', 2600.00);
-INSERT INTO EMPLOYEE(ID, DEPARTMENT_ID, MANAGER_ID, FIRST_NAME, LAST_NAME, EMAIL, PHONE_NUMBER, HIRE_DATE, JOB, SALARY) VALUES(104, 2, 2, 'First name employee #4', 'Last name employee #4', 'Email employee #4', 'Phone number employee #4', '2014-01-01', 'Job employee #4', 1000.00);
-INSERT INTO EMPLOYEE(ID, DEPARTMENT_ID, MANAGER_ID, FIRST_NAME, LAST_NAME, EMAIL, PHONE_NUMBER, HIRE_DATE, JOB, SALARY) VALUES(105, 2, 2, 'First name employee #5', 'Last name employee #5', 'Email employee #5', 'Phone number employee #5', '2014-01-01', 'Job employee #5', 1200.00);
-INSERT INTO EMPLOYEE(ID, DEPARTMENT_ID, MANAGER_ID, FIRST_NAME, LAST_NAME, EMAIL, PHONE_NUMBER, HIRE_DATE, JOB, SALARY) VALUES(106, 2, 2, 'First name employee #6', 'Last name employee #6', 'Email employee #6', 'Phone number employee #6', '2014-01-01', 'Job employee #6', 800.00);
-INSERT INTO EMPLOYEE(ID, DEPARTMENT_ID, MANAGER_ID, FIRST_NAME, LAST_NAME, EMAIL, PHONE_NUMBER, HIRE_DATE, JOB, SALARY) VALUES(107, 3, 3, 'First name employee #7', 'Last name employee #7', 'Email employee #7', 'Phone number employee #7', '2014-01-01', 'Job employee #7', 1400.00);
-INSERT INTO EMPLOYEE(ID, DEPARTMENT_ID, MANAGER_ID, FIRST_NAME, LAST_NAME, EMAIL, PHONE_NUMBER, HIRE_DATE, JOB, SALARY) VALUES(108, 4, 4, 'First name employee #8', 'Last name employee #8', 'Email employee #8', 'Phone number employee #8', '2014-01-01', 'Job employee #8', 800.00);
-INSERT INTO EMPLOYEE(ID, DEPARTMENT_ID, MANAGER_ID, FIRST_NAME, LAST_NAME, EMAIL, PHONE_NUMBER, HIRE_DATE, JOB, SALARY) VALUES(109, 4, 4, 'First name employee #9', 'Last name employee #9', 'Email employee #9', 'Phone number employee #9', '2014-01-01', 'Job employee #9', 1490.00);
-INSERT INTO EMPLOYEE(ID, DEPARTMENT_ID, MANAGER_ID, FIRST_NAME, LAST_NAME, EMAIL, PHONE_NUMBER, HIRE_DATE, JOB, SALARY) VALUES(110, 4, 4, 'First name employee #10', 'Last name employee #12', 'Email employee #10', 'Phone number employee #10', '2014-01-01', 'Job employee #10', 1600.00);
-INSERT INTO EMPLOYEE(ID, DEPARTMENT_ID, MANAGER_ID, FIRST_NAME, LAST_NAME, EMAIL, PHONE_NUMBER, HIRE_DATE, JOB, SALARY) VALUES(111, 5, 5, 'First name employee #11', 'Last name employee #11', 'Email employee #11', 'Phone number employee #11', '2014-01-01', 'Job employee #11', 400.00);
-
-INSERT INTO CARS.PARKING(ID, NAME, CAPACITY) VALUES(0, 'Parking #1', 10);
-INSERT INTO CARS.PARKING(ID, NAME, CAPACITY) VALUES(1, 'Parking #2', 20);
-INSERT INTO CARS.PARKING(ID, NAME, CAPACITY) VALUES(2, 'Parking #3', 30);
-
-INSERT INTO CARS.CAR(ID, PARKING_ID, NAME) VALUES(0, 0, 'Car #1');
-INSERT INTO CARS.CAR(ID, PARKING_ID, NAME) VALUES(1, 0, 'Car #2');
-INSERT INTO CARS.CAR(ID, PARKING_ID, NAME) VALUES(2, 0, 'Car #3');
-INSERT INTO CARS.CAR(ID, PARKING_ID, NAME) VALUES(3, 1, 'Car #4');
-INSERT INTO CARS.CAR(ID, PARKING_ID, NAME) VALUES(4, 1, 'Car #5');
-INSERT INTO CARS.CAR(ID, PARKING_ID, NAME) VALUES(5, 2, 'Car #6');
-INSERT INTO CARS.CAR(ID, PARKING_ID, NAME) VALUES(6, 2, 'Car #7');
-INSERT INTO CARS.CAR(ID, PARKING_ID, NAME) VALUES(7, 2, 'Car #8');
-INSERT INTO CARS.CAR(ID, PARKING_ID, NAME) VALUES(8, 2, 'Car #9');

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-agent/jdbc-drivers/README.txt
----------------------------------------------------------------------
diff --git a/modules/web-agent/jdbc-drivers/README.txt b/modules/web-agent/jdbc-drivers/README.txt
deleted file mode 100644
index cad43b7..0000000
--- a/modules/web-agent/jdbc-drivers/README.txt
+++ /dev/null
@@ -1,10 +0,0 @@
-Ignite Web Agent
-======================================
-
-If you are are planning to load cache type metadata from your existing databases
-you need to copy JDBC drivers in this folder.
-
-This is default folder for JDBC drivers.
-
-Also, you could specify custom folder using option: "-d CUSTOM_PATH_TO_FOLDER_WITH_JDBC_DRIVERS".
-

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-agent/logs/README.txt
----------------------------------------------------------------------
diff --git a/modules/web-agent/logs/README.txt b/modules/web-agent/logs/README.txt
deleted file mode 100644
index 3a220eb..0000000
--- a/modules/web-agent/logs/README.txt
+++ /dev/null
@@ -1,5 +0,0 @@
-Ignite Web Agent
-======================================
-
-This is folder for agent logs.
-

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-agent/pom.xml
----------------------------------------------------------------------
diff --git a/modules/web-agent/pom.xml b/modules/web-agent/pom.xml
deleted file mode 100644
index d87084f..0000000
--- a/modules/web-agent/pom.xml
+++ /dev/null
@@ -1,189 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-
-<!--
-  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.
--->
-
-<!--
-    POM file.
--->
-<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
-    <modelVersion>4.0.0</modelVersion>
-
-    <parent>
-        <groupId>org.apache.ignite</groupId>
-        <artifactId>ignite-parent</artifactId>
-        <version>1</version>
-        <relativePath>../../parent</relativePath>
-    </parent>
-
-    <artifactId>ignite-web-agent</artifactId>
-    <version>1.7.0-SNAPSHOT</version>
-
-    <properties>
-        <maven.build.timestamp.format>yyMMddHHmmss</maven.build.timestamp.format>
-    </properties>
-
-    <dependencies>
-        <dependency>
-            <groupId>io.socket</groupId>
-            <artifactId>socket.io-client</artifactId>
-            <version>0.7.0</version>
-        </dependency>
-
-        <dependency>
-            <groupId>com.fasterxml.jackson.datatype</groupId>
-            <artifactId>jackson-datatype-json-org</artifactId>
-            <version>${jackson2.version}</version>
-        </dependency>
-
-        <dependency>
-            <groupId>com.beust</groupId>
-            <artifactId>jcommander</artifactId>
-            <version>1.48</version>
-        </dependency>
-
-        <dependency>
-            <groupId>org.apache.httpcomponents</groupId>
-            <artifactId>httpclient</artifactId>
-            <version>${httpclient.version}</version>
-        </dependency>
-
-        <dependency>
-            <groupId>org.apache.ignite</groupId>
-            <artifactId>ignite-schema-import-db</artifactId>
-            <version>${project.version}</version>
-            <exclusions>
-                <exclusion>
-                    <groupId>org.gridgain</groupId>
-                    <artifactId>ignite-shmem</artifactId>
-                </exclusion>
-            </exclusions>
-        </dependency>
-
-        <dependency>
-            <groupId>org.apache.ignite</groupId>
-            <artifactId>ignite-indexing</artifactId>
-            <version>${project.version}</version>
-        </dependency>
-
-        <dependency>
-            <groupId>org.apache.ignite</groupId>
-            <artifactId>ignite-rest-http</artifactId>
-            <version>${project.version}</version>
-        </dependency>
-
-        <dependency>
-            <groupId>org.apache.ignite</groupId>
-            <artifactId>ignite-spring</artifactId>
-            <version>${project.version}</version>
-            <exclusions>
-                <exclusion>
-                    <groupId>org.springframework</groupId>
-                    <artifactId>spring-aop</artifactId>
-                </exclusion>
-                <exclusion>
-                    <groupId>org.springframework</groupId>
-                    <artifactId>spring-tx</artifactId>
-                </exclusion>
-                <exclusion>
-                    <groupId>org.springframework</groupId>
-                    <artifactId>spring-jdbc</artifactId>
-                </exclusion>
-            </exclusions>
-        </dependency>
-
-        <dependency>
-            <groupId>org.apache.ignite</groupId>
-            <artifactId>ignite-log4j</artifactId>
-            <version>${project.version}</version>
-        </dependency>
-    </dependencies>
-
-    <build>
-        <finalName>ignite-web-agent-${project.version}</finalName>
-
-        <plugins>
-            <plugin>
-                <artifactId>maven-jar-plugin</artifactId>
-                <version>2.5</version>
-
-                <configuration>
-                    <archive>
-                        <manifest>
-                            <mainClass>org.apache.ignite.console.agent.AgentLauncher</mainClass>
-                        </manifest>
-                        <manifestEntries>
-                            <Build-Time>${maven.build.timestamp}</Build-Time>
-                        </manifestEntries>
-                    </archive>
-                </configuration>
-            </plugin>
-
-            <plugin>
-                <groupId>org.apache.maven.plugins</groupId>
-                <artifactId>maven-shade-plugin</artifactId>
-                <version>2.4</version>
-
-                <executions>
-                    <execution>
-                        <phase>package</phase>
-                        <goals>
-                            <goal>shade</goal>
-                        </goals>
-
-                        <configuration>
-                            <createDependencyReducedPom>false</createDependencyReducedPom>
-                            <filters>
-                                <filter>
-                                    <artifact>*:*</artifact>
-                                    <excludes>
-                                        <exclude>META-INF/maven/**</exclude>
-                                    </excludes>
-                                </filter>
-                            </filters>
-                        </configuration>
-                    </execution>
-                </executions>
-            </plugin>
-
-            <plugin>
-                <groupId>org.apache.maven.plugins</groupId>
-                <artifactId>maven-assembly-plugin</artifactId>
-                <version>2.4</version>
-                <inherited>false</inherited>
-
-                <executions>
-                    <execution>
-                        <id>release-web-agent</id>
-                        <phase>package</phase>
-                        <goals>
-                            <goal>single</goal>
-                        </goals>
-                        <configuration>
-                            <descriptors>
-                                <descriptor>assembly/release-web-agent.xml</descriptor>
-                            </descriptors>
-                            <finalName>ignite-web-agent-${project.version}</finalName>
-                            <outputDirectory>target</outputDirectory>
-                            <appendAssemblyId>false</appendAssemblyId>
-                        </configuration>
-                    </execution>
-                </executions>
-            </plugin>
-        </plugins>
-    </build>
-</project>

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-agent/src/main/java/org/apache/ignite/console/agent/AgentConfiguration.java
----------------------------------------------------------------------
diff --git a/modules/web-agent/src/main/java/org/apache/ignite/console/agent/AgentConfiguration.java b/modules/web-agent/src/main/java/org/apache/ignite/console/agent/AgentConfiguration.java
deleted file mode 100644
index d4787cc..0000000
--- a/modules/web-agent/src/main/java/org/apache/ignite/console/agent/AgentConfiguration.java
+++ /dev/null
@@ -1,268 +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.
- */
-
-package org.apache.ignite.console.agent;
-
-import com.beust.jcommander.Parameter;
-import java.io.File;
-import java.io.IOException;
-import java.io.InputStreamReader;
-import java.io.Reader;
-import java.net.URL;
-import java.util.Arrays;
-import java.util.List;
-import java.util.Properties;
-
-/**
- * Agent configuration.
- */
-public class AgentConfiguration {
-    /** Default server port. */
-    public static final int DFLT_SERVER_PORT = 3001;
-
-    /** Default Ignite node HTTP port. */
-    public static final int DFLT_NODE_PORT = 8080;
-
-    /** Default path to agent property file. */
-    public static final String DFLT_CFG_PATH = "default.properties";
-
-    /** Default server URI. */
-    private static final String DFLT_SERVER_URI = "http://localhost:3001";
-
-    /** Default Ignite node HTTP URI. */
-    private static final String DFLT_NODE_URI = "http://localhost:8080";
-
-    /** */
-    @Parameter(names = {"-t", "--tokens"},
-        description = "User's tokens separated by comma used to connect to Ignite Console.")
-    private List<String> tokens;
-
-    /** */
-    @Parameter(names = {"-s", "--server-uri"},
-        description = "URI for connect to Ignite Console via web-socket protocol" +
-        "           " +
-        "      Default value: " + DFLT_SERVER_URI)
-    private String srvUri;
-
-    /** */
-    @Parameter(names = {"-n", "--node-uri"}, description = "URI for connect to Ignite node REST server" +
-        "                        " +
-        "      Default value: " + DFLT_NODE_URI)
-    private String nodeUri;
-
-    /** URI for connect to Ignite demo node REST server */
-    private String demoNodeUri;
-
-    /** */
-    @Parameter(names = {"-c", "--config"}, description = "Path to agent property file" +
-        "                                  " +
-        "      Default value: " + DFLT_CFG_PATH)
-    private String cfgPath;
-
-    /** */
-    @Parameter(names = {"-d", "--driver-folder"}, description = "Path to folder with JDBC drivers" +
-        "                             " +
-        "      Default value: ./jdbc-drivers")
-    private String driversFolder;
-
-    /** */
-    @Parameter(names = { "-h", "--help" }, help = true, description = "Print this help message")
-    private Boolean help;
-
-    /**
-     * @return Tokens.
-     */
-    public List<String> tokens() {
-        return tokens;
-    }
-
-    /**
-     * @param tokens Tokens.
-     */
-    public void tokens(List<String> tokens) {
-        this.tokens = tokens;
-    }
-
-    /**
-     * @return Server URI.
-     */
-    public String serverUri() {
-        return srvUri;
-    }
-
-    /**
-     * @param srvUri URI.
-     */
-    public void serverUri(String srvUri) {
-        this.srvUri = srvUri;
-    }
-
-    /**
-     * @return Node URI.
-     */
-    public String nodeUri() {
-        return nodeUri;
-    }
-
-    /**
-     * @param nodeUri Node URI.
-     */
-    public void nodeUri(String nodeUri) {
-        this.nodeUri = nodeUri;
-    }
-
-    /**
-     * @return Demo node URI.
-     */
-    public String demoNodeUri() {
-        return demoNodeUri;
-    }
-
-    /**
-     * @param demoNodeUri Demo node URI.
-     */
-    public void demoNodeUri(String demoNodeUri) {
-        this.demoNodeUri = demoNodeUri;
-    }
-
-    /**
-     * @return Configuration path.
-     */
-    public String configPath() {
-        return cfgPath == null ? DFLT_CFG_PATH : cfgPath;
-    }
-
-    /**
-     * @return Configured drivers folder.
-     */
-    public String driversFolder() {
-        return driversFolder;
-    }
-
-    /**
-     * @param driversFolder Driver folder.
-     */
-    public void driversFolder(String driversFolder) {
-        this.driversFolder = driversFolder;
-    }
-
-    /**
-     * @return {@code true} If agent options usage should be printed.
-     */
-    public Boolean help() {
-        return help != null ? help : Boolean.FALSE;
-    }
-
-    /**
-     * @param cfgUrl URL.
-     */
-    public void load(URL cfgUrl) throws IOException {
-        Properties props = new Properties();
-
-        try (Reader reader = new InputStreamReader(cfgUrl.openStream())) {
-            props.load(reader);
-        }
-
-        String val = (String)props.remove("tokens");
-
-        if (val != null)
-            tokens(Arrays.asList(val.split(",")));
-
-        val = (String)props.remove("server-uri");
-
-        if (val != null)
-            serverUri(val);
-
-        val = (String)props.remove("node-uri");
-
-        if (val != null)
-            nodeUri(val);
-
-        val = (String)props.remove("driver-folder");
-
-        if (val != null)
-            driversFolder(val);
-    }
-
-    /**
-     * @param cmd Command.
-     */
-    public void merge(AgentConfiguration cmd) {
-        if (tokens == null)
-            tokens(cmd.tokens());
-
-        if (srvUri == null)
-            serverUri(cmd.serverUri());
-
-        if (srvUri == null)
-            serverUri(DFLT_SERVER_URI);
-
-        if (nodeUri == null)
-            nodeUri(cmd.nodeUri());
-
-        if (nodeUri == null)
-            nodeUri(DFLT_NODE_URI);
-
-        if (driversFolder == null)
-            driversFolder(cmd.driversFolder());
-    }
-
-    /** {@inheritDoc} */
-    @Override public String toString() {
-        StringBuilder sb = new StringBuilder();
-
-        if (tokens != null && tokens.size() > 0) {
-            sb.append("User's security tokens        : ");
-
-            boolean first = true;
-
-            for (String tok : tokens) {
-                if (first)
-                    first = false;
-                else
-                    sb.append(",");
-
-                if (tok.length() > 4) {
-                    sb.append(new String(new char[tok.length() - 4]).replace('\0', '*'));
-
-                    sb.append(tok.substring(tok.length() - 4));
-                }
-                else
-                    sb.append(new String(new char[tok.length()]).replace('\0', '*'));
-            }
-
-            sb.append('\n');
-        }
-
-        sb.append("URI to Ignite node REST server: ").append(nodeUri == null ? DFLT_NODE_URI : nodeUri).append('\n');
-        sb.append("URI to Ignite Console server  : ").append(srvUri == null ? DFLT_SERVER_URI : srvUri).append('\n');
-        sb.append("Path to agent property file   : ").append(configPath()).append('\n');
-
-        String drvFld = driversFolder();
-
-        if (drvFld == null) {
-            File agentHome = AgentUtils.getAgentHome();
-
-            if (agentHome != null)
-                drvFld = new File(agentHome, "jdbc-drivers").getPath();
-        }
-
-        sb.append("Path to JDBC drivers folder   : ").append(drvFld);
-
-        return sb.toString();
-    }
-}

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-agent/src/main/java/org/apache/ignite/console/agent/AgentLauncher.java
----------------------------------------------------------------------
diff --git a/modules/web-agent/src/main/java/org/apache/ignite/console/agent/AgentLauncher.java b/modules/web-agent/src/main/java/org/apache/ignite/console/agent/AgentLauncher.java
deleted file mode 100644
index 810fad4..0000000
--- a/modules/web-agent/src/main/java/org/apache/ignite/console/agent/AgentLauncher.java
+++ /dev/null
@@ -1,344 +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.
- */
-
-package org.apache.ignite.console.agent;
-
-import com.beust.jcommander.JCommander;
-import com.beust.jcommander.ParameterException;
-import io.socket.client.Ack;
-import io.socket.client.IO;
-import io.socket.client.Socket;
-import io.socket.emitter.Emitter;
-import java.io.File;
-import java.io.IOException;
-import java.net.ConnectException;
-import java.net.URI;
-import java.net.URISyntaxException;
-import java.net.URL;
-import java.util.Arrays;
-import java.util.concurrent.CountDownLatch;
-import java.util.jar.Attributes;
-import java.util.jar.Manifest;
-import javax.net.ssl.SSLContext;
-import javax.net.ssl.SSLHandshakeException;
-import javax.net.ssl.TrustManager;
-import javax.net.ssl.X509TrustManager;
-import org.apache.ignite.console.agent.handlers.DatabaseHandler;
-import org.apache.ignite.console.agent.handlers.RestHandler;
-import org.apache.ignite.internal.util.typedef.X;
-import org.apache.log4j.Logger;
-import org.json.JSONException;
-import org.json.JSONObject;
-
-import static io.socket.client.Socket.EVENT_CONNECT;
-import static io.socket.client.Socket.EVENT_CONNECTING;
-import static io.socket.client.Socket.EVENT_CONNECT_ERROR;
-import static io.socket.client.Socket.EVENT_DISCONNECT;
-import static io.socket.client.Socket.EVENT_ERROR;
-import static io.socket.client.Socket.EVENT_RECONNECTING;
-import static org.apache.ignite.console.agent.AgentConfiguration.DFLT_SERVER_PORT;
-
-/**
- * Control Center Agent launcher.
- */
-public class AgentLauncher {
-    /** */
-    private static final Logger log = Logger.getLogger(AgentLauncher.class.getName());
-
-    /** */
-    private static final String EVENT_NODE_REST = "node:rest";
-
-    /** */
-    private static final String EVENT_SCHEMA_IMPORT_DRIVERS = "schemaImport:drivers";
-
-    /** */
-    private static final String EVENT_SCHEMA_IMPORT_SCHEMAS = "schemaImport:schemas";
-
-    /** */
-    private static final String EVENT_SCHEMA_IMPORT_METADATA = "schemaImport:metadata";
-
-    /** */
-    private static final String EVENT_AGENT_WARNING = "agent:warning";
-
-    /** */
-    private static final String EVENT_AGENT_CLOSE = "agent:close";
-
-    /** */
-    private static final int RECONNECT_INTERVAL = 3000;
-
-    /**
-     * Create a trust manager that trusts all certificates It is not using a particular keyStore
-     */
-    private static TrustManager[] getTrustManagers() {
-        return new TrustManager[] {
-            new X509TrustManager() {
-                public java.security.cert.X509Certificate[] getAcceptedIssuers() {
-                    return null;
-                }
-
-                public void checkClientTrusted(
-                    java.security.cert.X509Certificate[] certs, String authType) {
-                }
-
-                public void checkServerTrusted(
-                    java.security.cert.X509Certificate[] certs, String authType) {
-                }
-            }};
-    }
-
-    /**
-     * On error listener.
-     */
-    private static final Emitter.Listener onError = new Emitter.Listener() {
-        @SuppressWarnings("ThrowableResultOfMethodCallIgnored")
-        @Override public void call(Object... args) {
-            Throwable e = (Throwable)args[0];
-
-            ConnectException ce = X.cause(e, ConnectException.class);
-
-            if (ce != null)
-                log.error("Failed to receive response from server (connection refused).");
-            else {
-                Exception ignore = X.cause(e, SSLHandshakeException.class);
-
-                if (ignore != null) {
-                    log.error("Failed to establish SSL connection to server, due to errors with SSL handshake.");
-                    log.error("Add to environment variable JVM_OPTS parameter \"-Dtrust.all=true\" to skip certificate validation in case of using self-signed certificate.");
-
-                    System.exit(1);
-                }
-
-                ignore = X.cause(e, IOException.class);
-
-                if (ignore != null && "404".equals(ignore.getMessage())) {
-                    log.error("Failed to receive response from server (connection refused).");
-
-                    return;
-                }
-
-                log.error("Connection error.", e);
-            }
-        }
-    };
-
-    /**
-     * On disconnect listener.
-     */
-    private static final Emitter.Listener onDisconnect = new Emitter.Listener() {
-        @Override public void call(Object... args) {
-            log.error(String.format("Connection closed: %s.", args));
-        }
-    };
-
-    /**
-     * @param args Args.
-     */
-    @SuppressWarnings("BusyWait")
-    public static void main(String[] args) throws Exception {
-        log.info("Starting Apache Ignite Web Console Agent...");
-
-        final AgentConfiguration cfg = new AgentConfiguration();
-
-        JCommander jCommander = new JCommander(cfg);
-
-        String osName = System.getProperty("os.name").toLowerCase();
-
-        jCommander.setProgramName("ignite-web-agent." + (osName.contains("win") ? "bat" : "sh"));
-
-        try {
-            jCommander.parse(args);
-        }
-        catch (ParameterException pe) {
-            log.error("Failed to parse command line parameters: " + Arrays.toString(args), pe);
-
-            jCommander.usage();
-
-            return;
-        }
-
-        String prop = cfg.configPath();
-
-        AgentConfiguration propCfg = new AgentConfiguration();
-
-        try {
-            File f = AgentUtils.resolvePath(prop);
-
-            if (f == null)
-                log.warn("Failed to find agent property file: " + prop);
-            else
-                propCfg.load(f.toURI().toURL());
-        }
-        catch (IOException ignore) {
-            if (!AgentConfiguration.DFLT_CFG_PATH.equals(prop))
-                log.warn("Failed to load agent property file: " + prop, ignore);
-        }
-
-        cfg.merge(propCfg);
-
-        if (cfg.help()) {
-            jCommander.usage();
-
-            return;
-        }
-
-        System.out.println();
-        System.out.println("Agent configuration:");
-        System.out.println(cfg);
-        System.out.println();
-
-        if (cfg.tokens() == null) {
-            String webHost;
-
-            try {
-                webHost = new URI(cfg.serverUri()).getHost();
-            }
-            catch (URISyntaxException e) {
-                log.error("Failed to parse Ignite Web Console uri", e);
-
-                return;
-            }
-
-            System.out.println("Security token is required to establish connection to the web console.");
-            System.out.println(String.format("It is available on the Profile page: https://%s/profile", webHost));
-
-            System.out.print("Enter security tokens separated by comma: ");
-
-            cfg.tokens(Arrays.asList(System.console().readLine().trim().split(",")));
-        }
-
-        final RestHandler restHnd = new RestHandler(cfg);
-
-        try {
-            restHnd.start();
-
-            URI uri = URI.create(cfg.serverUri());
-
-            if (uri.getPort() == -1)
-                uri = URI.create(cfg.serverUri() + ':' + DFLT_SERVER_PORT);
-
-            IO.Options opts = new IO.Options();
-
-            opts.reconnectionDelay = RECONNECT_INTERVAL;
-
-            // Workaround for use self-signed certificate
-            if (Boolean.getBoolean("trust.all")) {
-                SSLContext ctx = SSLContext.getInstance("TLS");
-
-                // Create an SSLContext that uses our TrustManager
-                ctx.init(null, getTrustManagers(), null);
-
-                opts.sslContext = ctx;
-            }
-
-            final Socket client = IO.socket(uri, opts);
-
-            try {
-                Emitter.Listener onConnecting = new Emitter.Listener() {
-                    @Override public void call(Object... args) {
-                        log.info("Connecting to: " + cfg.serverUri());
-                    }
-                };
-
-                Emitter.Listener onConnect = new Emitter.Listener() {
-                    @Override public void call(Object... args) {
-                        log.info("Connection established.");
-
-                        JSONObject authMsg = new JSONObject();
-
-                        try {
-                            authMsg.put("tokens", cfg.tokens());
-
-                            String clsName = AgentLauncher.class.getSimpleName() + ".class";
-
-                            String clsPath = AgentLauncher.class.getResource(clsName).toString();
-
-                            if (clsPath.startsWith("jar")) {
-                                String manifestPath = clsPath.substring(0, clsPath.lastIndexOf('!') + 1) +
-                                    "/META-INF/MANIFEST.MF";
-
-                                Manifest manifest = new Manifest(new URL(manifestPath).openStream());
-
-                                Attributes attr = manifest.getMainAttributes();
-
-                                authMsg.put("ver", attr.getValue("Implementation-Version"));
-                                authMsg.put("bt", attr.getValue("Build-Time"));
-                            }
-
-                            client.emit("agent:auth", authMsg, new Ack() {
-                                @Override public void call(Object... args) {
-                                    // Authentication failed if response contains args.
-                                    if (args != null && args.length > 0) {
-                                        onDisconnect.call(args);
-
-                                        System.exit(1);
-                                    }
-
-                                    log.info("Authentication success.");
-                                }
-                            });
-                        }
-                        catch (JSONException | IOException e) {
-                            log.error("Failed to construct authentication message", e);
-
-                            client.close();
-                        }
-                    }
-                };
-
-                DatabaseHandler dbHnd = new DatabaseHandler(cfg);
-
-                final CountDownLatch latch = new CountDownLatch(1);
-
-                client
-                    .on(EVENT_CONNECTING, onConnecting)
-                    .on(EVENT_CONNECT, onConnect)
-                    .on(EVENT_CONNECT_ERROR, onError)
-                    .on(EVENT_RECONNECTING, onConnecting)
-                    .on(EVENT_NODE_REST, restHnd)
-                    .on(EVENT_SCHEMA_IMPORT_DRIVERS, dbHnd.availableDriversListener())
-                    .on(EVENT_SCHEMA_IMPORT_SCHEMAS, dbHnd.schemasListener())
-                    .on(EVENT_SCHEMA_IMPORT_METADATA, dbHnd.metadataListener())
-                    .on(EVENT_ERROR, onError)
-                    .on(EVENT_DISCONNECT, onDisconnect)
-                    .on(EVENT_AGENT_WARNING, new Emitter.Listener() {
-                        @Override public void call(Object... args) {
-                            log.warn(args[0]);
-                        }
-                    })
-                    .on(EVENT_AGENT_CLOSE, new Emitter.Listener() {
-                        @Override public void call(Object... args) {
-                            onDisconnect.call(args);
-
-                            client.off();
-
-                            latch.countDown();
-                        }
-                    });
-
-                client.connect();
-
-                latch.await();
-            }
-            finally {
-                client.close();
-            }
-        }
-        finally {
-            restHnd.stop();
-        }
-    }
-}

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-agent/src/main/java/org/apache/ignite/console/agent/AgentUtils.java
----------------------------------------------------------------------
diff --git a/modules/web-agent/src/main/java/org/apache/ignite/console/agent/AgentUtils.java b/modules/web-agent/src/main/java/org/apache/ignite/console/agent/AgentUtils.java
deleted file mode 100644
index 50a849a..0000000
--- a/modules/web-agent/src/main/java/org/apache/ignite/console/agent/AgentUtils.java
+++ /dev/null
@@ -1,111 +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.
- */
-
-package org.apache.ignite.console.agent;
-
-import java.io.File;
-import java.net.URI;
-import java.net.URISyntaxException;
-import java.security.ProtectionDomain;
-import org.apache.log4j.Logger;
-
-/**
- * Utility methods.
- */
-public class AgentUtils {
-    /** */
-    private static final Logger log = Logger.getLogger(AgentUtils.class.getName());
-
-    /**
-     * Default constructor.
-     */
-    private AgentUtils() {
-        // No-op.
-    }
-
-    /**
-     * @param path Path to normalize.
-     * @return Normalized file path.
-     */
-    public static String normalizePath(String path) {
-        return path != null ? path.replace('\\', '/') : null;
-    }
-
-    /**
-     * @return App folder.
-     */
-    public static File getAgentHome() {
-        try {
-            ProtectionDomain domain = AgentLauncher.class.getProtectionDomain();
-
-            // Should not happen, but to make sure our code is not broken.
-            if (domain == null || domain.getCodeSource() == null || domain.getCodeSource().getLocation() == null) {
-                log.warn("Failed to resolve agent jar location!");
-
-                return null;
-            }
-
-            // Resolve path to class-file.
-            URI classesUri = domain.getCodeSource().getLocation().toURI();
-
-            boolean win = System.getProperty("os.name").toLowerCase().contains("win");
-
-            // Overcome UNC path problem on Windows (http://www.tomergabel.com/JavaMishandlesUNCPathsOnWindows.aspx)
-            if (win && classesUri.getAuthority() != null)
-                classesUri = new URI(classesUri.toString().replace("file://", "file:/"));
-
-            return new File(classesUri).getParentFile();
-        }
-        catch (URISyntaxException | SecurityException ignored) {
-            log.warn("Failed to resolve agent jar location!");
-
-            return null;
-        }
-    }
-
-    /**
-     * Gets file associated with path.
-     * <p>
-     * First check if path is relative to agent home.
-     * If not, check if path is absolute.
-     * If all checks fail, then {@code null} is returned.
-     * <p>
-     *
-     * @param path Path to resolve.
-     * @return Resolved path as file, or {@code null} if path cannot be resolved.
-     */
-    public static File resolvePath(String path) {
-        assert path != null;
-
-        File home = getAgentHome();
-
-        if (home != null) {
-            File file = new File(home, normalizePath(path));
-
-            if (file.exists())
-                return file;
-        }
-
-        // 2. Check given path as absolute.
-        File file = new File(path);
-
-        if (file.exists())
-            return file;
-
-        return null;
-    }
-}

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-agent/src/main/java/org/apache/ignite/console/agent/handlers/AbstractHandler.java
----------------------------------------------------------------------
diff --git a/modules/web-agent/src/main/java/org/apache/ignite/console/agent/handlers/AbstractHandler.java b/modules/web-agent/src/main/java/org/apache/ignite/console/agent/handlers/AbstractHandler.java
deleted file mode 100644
index 7e4e320..0000000
--- a/modules/web-agent/src/main/java/org/apache/ignite/console/agent/handlers/AbstractHandler.java
+++ /dev/null
@@ -1,110 +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.
- */
-
-package org.apache.ignite.console.agent.handlers;
-
-import com.fasterxml.jackson.annotation.JsonAutoDetect;
-import com.fasterxml.jackson.annotation.PropertyAccessor;
-import com.fasterxml.jackson.databind.ObjectMapper;
-import com.fasterxml.jackson.datatype.jsonorg.JsonOrgModule;
-import io.socket.client.Ack;
-import io.socket.emitter.Emitter;
-import java.util.Arrays;
-import java.util.Collections;
-import java.util.Map;
-import org.json.JSONArray;
-import org.json.JSONObject;
-
-/**
- * Base class for web socket handlers.
- */
-abstract class AbstractHandler implements Emitter.Listener {
-    /** JSON object mapper. */
-    private static final ObjectMapper mapper = new ObjectMapper();
-
-    static {
-        JsonOrgModule module = new JsonOrgModule();
-
-        mapper.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.NONE);
-        mapper.setVisibility(PropertyAccessor.FIELD, JsonAutoDetect.Visibility.ANY);
-
-        mapper.registerModule(module);
-    }
-
-    /**
-     * @param obj Object.
-     * @return {@link JSONObject} or {@link JSONArray}.
-     */
-    private Object toJSON(Object obj) {
-        if (obj instanceof Iterable)
-            return mapper.convertValue(obj, JSONArray.class);
-
-        return mapper.convertValue(obj, JSONObject.class);
-    }
-
-    /** {@inheritDoc} */
-    @SuppressWarnings("unchecked")
-    @Override public final void call(Object... args) {
-        Ack cb = null;
-
-        try {
-            if (args == null || args.length == 0)
-                throw new IllegalArgumentException("Missing arguments.");
-
-            if (args.length > 2)
-                throw new IllegalArgumentException("Wrong arguments count, must be <= 2: " + Arrays.toString(args));
-
-            JSONObject lsnrArgs = null;
-
-            if (args.length == 1) {
-                if (args[0] instanceof JSONObject)
-                    lsnrArgs = (JSONObject)args[0];
-                else if (args[0] instanceof Ack)
-                    cb = (Ack)args[0];
-                else
-                    throw new IllegalArgumentException("Wrong type of argument, must be JSONObject or Ack: " + args[0]);
-            }
-            else {
-                if (args[0] != null && !(args[0] instanceof JSONObject))
-                    throw new IllegalArgumentException("Wrong type of argument, must be JSONObject: " + args[0]);
-
-                if (!(args[1] instanceof Ack))
-                    throw new IllegalArgumentException("Wrong type of argument, must be Ack: " + args[1]);
-
-                lsnrArgs = (JSONObject)args[0];
-
-                cb = (Ack)args[1];
-            }
-
-            Object res = execute(lsnrArgs == null ? Collections.emptyMap() : mapper.convertValue(lsnrArgs, Map.class));
-
-            if (cb != null)
-                cb.call(null, toJSON(res));
-        }
-        catch (Exception e) {
-            if (cb != null)
-                cb.call(e, null);
-        }
-    }
-
-    /**
-     * Execute command with specified arguments.
-     *
-     * @param args Map with method args.
-     */
-    public abstract Object execute(Map<String, Object> args) throws Exception;
-}

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-agent/src/main/java/org/apache/ignite/console/agent/handlers/DatabaseHandler.java
----------------------------------------------------------------------
diff --git a/modules/web-agent/src/main/java/org/apache/ignite/console/agent/handlers/DatabaseHandler.java b/modules/web-agent/src/main/java/org/apache/ignite/console/agent/handlers/DatabaseHandler.java
deleted file mode 100644
index 02146d9..0000000
--- a/modules/web-agent/src/main/java/org/apache/ignite/console/agent/handlers/DatabaseHandler.java
+++ /dev/null
@@ -1,298 +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.
- */
-
-package org.apache.ignite.console.agent.handlers;
-
-import io.socket.emitter.Emitter;
-import java.io.BufferedReader;
-import java.io.File;
-import java.io.FilenameFilter;
-import java.io.IOException;
-import java.io.InputStreamReader;
-import java.net.URL;
-import java.sql.Connection;
-import java.sql.SQLException;
-import java.util.ArrayList;
-import java.util.Collection;
-import java.util.Collections;
-import java.util.List;
-import java.util.Map;
-import java.util.Properties;
-import org.apache.ignite.console.agent.AgentConfiguration;
-import org.apache.ignite.console.demo.AgentMetadataDemo;
-import org.apache.ignite.schema.parser.DbMetadataReader;
-import org.apache.ignite.schema.parser.DbTable;
-import org.apache.log4j.Logger;
-
-import static org.apache.ignite.console.agent.AgentUtils.resolvePath;
-
-/**
- * API to extract database metadata.
- */
-public class DatabaseHandler {
-    /** */
-    private static final Logger log = Logger.getLogger(DatabaseHandler.class.getName());
-
-    /** */
-    private final File driversFolder;
-
-    /**
-     * @param cfg Config.
-     */
-    public DatabaseHandler(AgentConfiguration cfg) {
-        driversFolder = resolvePath(cfg.driversFolder() == null ? "jdbc-drivers" : cfg.driversFolder());
-    }
-
-    /**
-     * @param jdbcDriverJarPath JDBC driver JAR path.
-     * @param jdbcDriverCls JDBC driver class.
-     * @param jdbcUrl JDBC URL.
-     * @param jdbcInfo Properties to connect to database.
-     * @return Connection to database.
-     * @throws SQLException
-     */
-    private Connection connect(String jdbcDriverJarPath, String jdbcDriverCls, String jdbcUrl,
-        Properties jdbcInfo) throws SQLException {
-        if (AgentMetadataDemo.isTestDriveUrl(jdbcUrl))
-            return AgentMetadataDemo.testDrive();
-
-        if (!new File(jdbcDriverJarPath).isAbsolute() && driversFolder != null)
-            jdbcDriverJarPath = new File(driversFolder, jdbcDriverJarPath).getPath();
-
-        return DbMetadataReader.getInstance().connect(jdbcDriverJarPath, jdbcDriverCls, jdbcUrl, jdbcInfo);
-    }
-
-    /**
-     * @param jdbcDriverJarPath JDBC driver JAR path.
-     * @param jdbcDriverCls JDBC driver class.
-     * @param jdbcUrl JDBC URL.
-     * @param jdbcInfo Properties to connect to database.
-     * @return Collection of schema names.
-     * @throws SQLException
-     */
-    protected Collection<String> schemas(String jdbcDriverJarPath, String jdbcDriverCls, String jdbcUrl,
-        Properties jdbcInfo) throws SQLException {
-        if (log.isDebugEnabled())
-            log.debug("Start collecting database schemas [drvJar=" + jdbcDriverJarPath +
-                ", drvCls=" + jdbcDriverCls + ", jdbcUrl=" + jdbcUrl + "]");
-
-        try (Connection conn = connect(jdbcDriverJarPath, jdbcDriverCls, jdbcUrl, jdbcInfo)) {
-            Collection<String> schemas = DbMetadataReader.getInstance().schemas(conn);
-
-            if (log.isDebugEnabled())
-                log.debug("Finished collection of schemas [jdbcUrl=" + jdbcUrl + ", count=" + schemas.size() + "]");
-
-            return schemas;
-        }
-        catch (Throwable e) {
-            log.error("Failed to collect schemas", e);
-
-            throw new SQLException("Failed to collect schemas", e);
-        }
-    }
-
-    /**
-     * Listener for schema names.
-     *
-     * @return Collection of schema names.
-     */
-    public Emitter.Listener schemasListener() {
-        return new AbstractHandler() {
-            @Override public Object execute(Map<String, Object> args) throws Exception {
-                String driverPath = null;
-
-                if (args.containsKey("driverPath"))
-                    driverPath = args.get("driverPath").toString();
-
-                if (!args.containsKey("driverClass"))
-                    throw new IllegalArgumentException("Missing driverClass in arguments: " + args);
-
-                String driverCls = args.get("driverClass").toString();
-
-                if (!args.containsKey("url"))
-                    throw new IllegalArgumentException("Missing url in arguments: " + args);
-
-                String url = args.get("url").toString();
-
-                if (!args.containsKey("info"))
-                    throw new IllegalArgumentException("Missing info in arguments: " + args);
-
-                Properties info = new Properties();
-
-                info.putAll((Map)args.get("info"));
-
-                return schemas(driverPath, driverCls, url, info);
-            }
-        };
-    }
-
-    /**
-     * @param jdbcDriverJarPath JDBC driver JAR path.
-     * @param jdbcDriverCls JDBC driver class.
-     * @param jdbcUrl JDBC URL.
-     * @param jdbcInfo Properties to connect to database.
-     * @param schemas List of schema names to process.
-     * @param tblsOnly If {@code true} then only tables will be processed otherwise views also will be processed.
-     * @return Collection of tables.
-     */
-    protected Collection<DbTable> metadata(String jdbcDriverJarPath, String jdbcDriverCls, String jdbcUrl,
-        Properties jdbcInfo, List<String> schemas, boolean tblsOnly) throws SQLException {
-        if (log.isDebugEnabled())
-            log.debug("Start collecting database metadata [drvJar=" + jdbcDriverJarPath +
-                ", drvCls=" + jdbcDriverCls + ", jdbcUrl=" + jdbcUrl + "]");
-
-        try (Connection conn = connect(jdbcDriverJarPath, jdbcDriverCls, jdbcUrl, jdbcInfo)) {
-            Collection<DbTable> metadata = DbMetadataReader.getInstance().metadata(conn, schemas, tblsOnly);
-
-            if (log.isDebugEnabled())
-                log.debug("Finished collection of metadata [jdbcUrl=" + jdbcUrl + ", count=" + metadata.size() + "]");
-
-            return metadata;
-        }
-        catch (Throwable e) {
-            log.error("Failed to collect metadata", e);
-
-            throw new SQLException("Failed to collect metadata", e);
-        }
-    }
-
-    /**
-     * Listener for tables.
-     *
-     * @return Collection of tables.
-     */
-    public Emitter.Listener metadataListener() {
-        return new AbstractHandler() {
-            @SuppressWarnings("unchecked")
-            @Override public Object execute(Map<String, Object> args) throws Exception {
-                String driverPath = null;
-
-                if (args.containsKey("driverPath"))
-                    driverPath = args.get("driverPath").toString();
-
-                if (!args.containsKey("driverClass"))
-                    throw new IllegalArgumentException("Missing driverClass in arguments: " + args);
-
-                String driverCls = args.get("driverClass").toString();
-
-                if (!args.containsKey("url"))
-                    throw new IllegalArgumentException("Missing url in arguments: " + args);
-
-                String url = args.get("url").toString();
-
-                if (!args.containsKey("info"))
-                    throw new IllegalArgumentException("Missing info in arguments: " + args);
-
-                Properties info = new Properties();
-
-                info.putAll((Map)args.get("info"));
-
-                if (!args.containsKey("schemas"))
-                    throw new IllegalArgumentException("Missing schemas in arguments: " + args);
-
-                List<String> schemas = (List<String>)args.get("schemas");
-
-                if (!args.containsKey("tablesOnly"))
-                    throw new IllegalArgumentException("Missing tablesOnly in arguments: " + args);
-
-                boolean tblsOnly = (boolean)args.get("tablesOnly");
-
-                return metadata(driverPath, driverCls, url, info, schemas, tblsOnly);
-            }
-        };
-    }
-
-    /**
-     * Listener for drivers.
-     *
-     * @return Drivers in drivers folder
-     * @see AgentConfiguration#driversFolder
-     */
-    public Emitter.Listener availableDriversListener() {
-        return new AbstractHandler() {
-            @Override public Object execute(Map<String, Object> args) throws Exception {
-                if (driversFolder == null) {
-                    log.info("JDBC drivers folder not specified, returning empty list");
-
-                    return Collections.emptyList();
-                }
-
-                if (log.isDebugEnabled())
-                    log.debug("Collecting JDBC drivers in folder: " + driversFolder.getPath());
-
-                File[] list = driversFolder.listFiles(new FilenameFilter() {
-                    @Override public boolean accept(File dir, String name) {
-                        return name.endsWith(".jar");
-                    }
-                });
-
-                if (list == null) {
-                    log.info("JDBC drivers folder has no files, returning empty list");
-
-                    return Collections.emptyList();
-                }
-
-                List<JdbcDriver> res = new ArrayList<>();
-
-                for (File file : list) {
-                    try {
-                        boolean win = System.getProperty("os.name").contains("win");
-
-                        URL url = new URL("jar", null,
-                            "file:" + (win ? "/" : "") + file.getPath() + "!/META-INF/services/java.sql.Driver");
-
-                        try (BufferedReader reader = new BufferedReader(new InputStreamReader(url.openStream()))) {
-                            String jdbcDriverCls = reader.readLine();
-
-                            res.add(new JdbcDriver(file.getName(), jdbcDriverCls));
-
-                            if (log.isDebugEnabled())
-                                log.debug("Found: [driver=" + file + ", class=" + jdbcDriverCls + "]");
-                        }
-                    }
-                    catch (IOException e) {
-                        res.add(new JdbcDriver(file.getName(), null));
-
-                        log.info("Found: [driver=" + file + "]");
-                        log.info("Failed to detect driver class: " + e.getMessage());
-                    }
-                }
-
-                return res;
-            }
-        };
-    }
-
-    /**
-     * Wrapper class for later to be transformed to JSON and send to Web Console.
-     */
-    private static class JdbcDriver {
-        /** */
-        public final String jdbcDriverJar;
-        /** */
-        public final String jdbcDriverCls;
-
-        /**
-         * @param jdbcDriverJar File name of driver jar file.
-         * @param jdbcDriverCls Optional JDBC driver class.
-         */
-        public JdbcDriver(String jdbcDriverJar, String jdbcDriverCls) {
-            this.jdbcDriverJar = jdbcDriverJar;
-            this.jdbcDriverCls = jdbcDriverCls;
-        }
-    }
-}

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-agent/src/main/java/org/apache/ignite/console/agent/handlers/RestHandler.java
----------------------------------------------------------------------
diff --git a/modules/web-agent/src/main/java/org/apache/ignite/console/agent/handlers/RestHandler.java b/modules/web-agent/src/main/java/org/apache/ignite/console/agent/handlers/RestHandler.java
deleted file mode 100644
index 1b4b565..0000000
--- a/modules/web-agent/src/main/java/org/apache/ignite/console/agent/handlers/RestHandler.java
+++ /dev/null
@@ -1,276 +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.
- */
-
-package org.apache.ignite.console.agent.handlers;
-
-import java.io.ByteArrayOutputStream;
-import java.io.IOException;
-import java.net.ConnectException;
-import java.net.URISyntaxException;
-import java.nio.charset.Charset;
-import java.util.List;
-import java.util.Map;
-import org.apache.commons.codec.Charsets;
-import org.apache.http.Header;
-import org.apache.http.NameValuePair;
-import org.apache.http.client.entity.UrlEncodedFormEntity;
-import org.apache.http.client.methods.CloseableHttpResponse;
-import org.apache.http.client.methods.HttpGet;
-import org.apache.http.client.methods.HttpPost;
-import org.apache.http.client.methods.HttpRequestBase;
-import org.apache.http.client.utils.URIBuilder;
-import org.apache.http.entity.StringEntity;
-import org.apache.http.impl.client.CloseableHttpClient;
-import org.apache.http.impl.client.HttpClientBuilder;
-import org.apache.ignite.console.agent.AgentConfiguration;
-import org.apache.ignite.console.demo.AgentClusterDemo;
-import org.apache.log4j.Logger;
-
-import static org.apache.ignite.console.agent.AgentConfiguration.DFLT_NODE_PORT;
-
-/**
- * API to translate REST requests to Ignite cluster.
- */
-public class RestHandler extends AbstractHandler {
-    /** */
-    private static final Logger log = Logger.getLogger(RestHandler.class.getName());
-
-    /** */
-    private final AgentConfiguration cfg;
-
-    /** */
-    private CloseableHttpClient httpClient;
-
-    /**
-     * @param cfg Config.
-     */
-    public RestHandler(AgentConfiguration cfg) {
-        this.cfg = cfg;
-    }
-
-    /**
-     * Start HTTP client for communication with node via REST.
-     */
-    public void start() {
-        httpClient = HttpClientBuilder.create().build();
-    }
-
-    /**
-     * Stop HTTP client.
-     */
-    public void stop() {
-        if (httpClient != null) {
-            try {
-                httpClient.close();
-            }
-            catch (IOException ignore) {
-                // No-op.
-            }
-        }
-    }
-
-    /** {@inheritDoc} */
-    @SuppressWarnings("unchecked")
-    @Override public Object execute(Map<String, Object> args) throws Exception {
-        if (log.isDebugEnabled())
-            log.debug("Start parse REST command args: " + args);
-
-        String uri = null;
-
-        if (args.containsKey("uri"))
-            uri = args.get("uri").toString();
-
-        Map<String, Object> params = null;
-
-        if (args.containsKey("params"))
-            params = (Map<String, Object>)args.get("params");
-
-        if (!args.containsKey("demo"))
-            throw new IllegalArgumentException("Missing demo flag in arguments: " + args);
-
-        boolean demo = (boolean)args.get("demo");
-
-        if (!args.containsKey("method"))
-            throw new IllegalArgumentException("Missing method in arguments: " + args);
-
-        String mtd = args.get("method").toString();
-
-        Map<String, Object> headers = null;
-
-        if (args.containsKey("headers"))
-            headers = (Map<String, Object>)args.get("headers");
-
-        String body = null;
-
-        if (args.containsKey("body"))
-            body = args.get("body").toString();
-
-        return executeRest(uri, params, demo, mtd, headers, body);
-    }
-
-    /**
-     * @param uri Url.
-     * @param params Params.
-     * @param demo Use demo node.
-     * @param mtd Method.
-     * @param headers Headers.
-     * @param body Body.
-     */
-    protected RestResult executeRest(String uri, Map<String, Object> params, boolean demo,
-        String mtd, Map<String, Object> headers, String body) throws IOException, URISyntaxException {
-        if (log.isDebugEnabled())
-            log.debug("Start execute REST command [method=" + mtd + ", uri=/" + (uri == null ? "" : uri) +
-                ", parameters=" + params + "]");
-
-        final URIBuilder builder;
-
-        if (demo) {
-            // try start demo if needed.
-            AgentClusterDemo.testDrive(cfg);
-
-            // null if demo node not started yet.
-            if (cfg.demoNodeUri() == null)
-                return RestResult.fail("Demo node is not started yet.", 404);
-
-            builder = new URIBuilder(cfg.demoNodeUri());
-        }
-        else
-            builder = new URIBuilder(cfg.nodeUri());
-
-        if (builder.getPort() == -1)
-            builder.setPort(DFLT_NODE_PORT);
-
-        if (uri != null) {
-            if (!uri.startsWith("/") && !cfg.nodeUri().endsWith("/"))
-                uri = '/' + uri;
-
-            builder.setPath(uri);
-        }
-
-        if (params != null) {
-            for (Map.Entry<String, Object> entry : params.entrySet()) {
-                if (entry.getValue() != null)
-                    builder.addParameter(entry.getKey(), entry.getValue().toString());
-            }
-        }
-
-        HttpRequestBase httpReq = null;
-
-        try {
-            if ("GET".equalsIgnoreCase(mtd))
-                httpReq = new HttpGet(builder.build());
-            else if ("POST".equalsIgnoreCase(mtd)) {
-                HttpPost post;
-
-                if (body == null) {
-                    List<NameValuePair> nvps = builder.getQueryParams();
-
-                    builder.clearParameters();
-
-                    post = new HttpPost(builder.build());
-
-                    if (!nvps.isEmpty())
-                        post.setEntity(new UrlEncodedFormEntity(nvps));
-                }
-                else {
-                    post = new HttpPost(builder.build());
-
-                    post.setEntity(new StringEntity(body));
-                }
-
-                httpReq = post;
-            }
-            else
-                throw new IOException("Unknown HTTP-method: " + mtd);
-
-            if (headers != null) {
-                for (Map.Entry<String, Object> entry : headers.entrySet())
-                    httpReq.addHeader(entry.getKey(), entry.getValue() == null ? null : entry.getValue().toString());
-            }
-
-            try (CloseableHttpResponse resp = httpClient.execute(httpReq)) {
-                ByteArrayOutputStream out = new ByteArrayOutputStream();
-
-                resp.getEntity().writeTo(out);
-
-                Charset charset = Charsets.UTF_8;
-
-                Header encodingHdr = resp.getEntity().getContentEncoding();
-
-                if (encodingHdr != null) {
-                    String encoding = encodingHdr.getValue();
-
-                    charset = Charsets.toCharset(encoding);
-                }
-
-                return RestResult.success(resp.getStatusLine().getStatusCode(), new String(out.toByteArray(), charset));
-            }
-            catch (ConnectException e) {
-                log.info("Failed connect to node and execute REST command [uri=" + builder.build() + "]");
-
-                return RestResult.fail("Failed connect to node and execute REST command.", 404);
-            }
-        }
-        finally {
-            if (httpReq != null)
-                httpReq.reset();
-        }
-    }
-
-    /**
-     * Request result.
-     */
-    public static class RestResult {
-        /** The field contains description of error if server could not handle the request. */
-        public final String error;
-
-        /** REST http code. */
-        public final int code;
-
-        /** The field contains result of command. */
-        public final String data;
-
-        /**
-         * @param error The field contains description of error if server could not handle the request.
-         * @param resCode REST http code.
-         * @param res The field contains result of command.
-         */
-        private RestResult(String error, int resCode, String res) {
-            this.error = error;
-            this.code = resCode;
-            this.data = res;
-        }
-
-        /**
-         * @param error The field contains description of error if server could not handle the request.
-         * @param restCode REST http code.
-         * @return Request result.
-         */
-        public static RestResult fail(String error, int restCode) {
-            return new RestResult(error, restCode, null);
-        }
-
-        /**
-         * @param code REST http code.
-         * @param data The field contains result of command.
-         * @return Request result.
-         */
-        public static RestResult success(int code, String data) {
-            return new RestResult(null, code, data);
-        }
-    }
-}


[36/52] ignite git commit: Web Console beta-3.

Posted by ak...@apache.org.
http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/frontend/app/modules/sql/sql.controller.js
----------------------------------------------------------------------
diff --git a/modules/web-console/frontend/app/modules/sql/sql.controller.js b/modules/web-console/frontend/app/modules/sql/sql.controller.js
new file mode 100644
index 0000000..92eb7be
--- /dev/null
+++ b/modules/web-console/frontend/app/modules/sql/sql.controller.js
@@ -0,0 +1,1632 @@
+/*
+ * 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.
+ */
+
+// Time line X axis descriptor.
+const TIME_LINE = {value: -1, type: 'java.sql.Date', label: 'TIME_LINE'};
+
+// Row index X axis descriptor.
+const ROW_IDX = {value: -2, type: 'java.lang.Integer', label: 'ROW_IDX'};
+
+/** Prefix for node local key for SCAN near queries. */
+const SCAN_CACHE_WITH_FILTER = 'VISOR_SCAN_CACHE_WITH_FILTER';
+
+/** Prefix for node local key for SCAN near queries. */
+const SCAN_CACHE_WITH_FILTER_CASE_SENSITIVE = 'VISOR_SCAN_CACHE_WITH_FILTER_CASE_SENSITIVE';
+
+const _fullColName = (col) => {
+    const res = [];
+
+    if (col.schemaName)
+        res.push(col.schemaName);
+
+    if (col.typeName)
+        res.push(col.typeName);
+
+    res.push(col.fieldName);
+
+    return res.join('.');
+};
+
+let paragraphId = 0;
+
+class Paragraph {
+    constructor($animate, $timeout, paragraph) {
+        const self = this;
+
+        self.id = 'paragraph-' + paragraphId++;
+
+        _.assign(this, paragraph);
+
+        Object.defineProperty(this, 'gridOptions', {value: {
+            enableGridMenu: false,
+            enableColumnMenus: false,
+            flatEntityAccess: true,
+            fastWatch: true,
+            rebuildColumns() {
+                if (_.isNil(this.api))
+                    return;
+
+                this.columnDefs = _.reduce(self.meta, (cols, col, idx) => {
+                    if (self.columnFilter(col)) {
+                        cols.push({
+                            displayName: col.fieldName,
+                            headerTooltip: _fullColName(col),
+                            field: idx.toString(),
+                            minWidth: 50,
+                            cellClass: 'cell-left'
+                        });
+                    }
+
+                    return cols;
+                }, []);
+
+                $timeout(() => this.api.core.notifyDataChange('column'));
+            },
+            adjustHeight() {
+                if (_.isNil(this.api))
+                    return;
+
+                this.data = self.rows;
+
+                const height = Math.min(self.rows.length, 15) * 30 + 47;
+
+                // Remove header height.
+                this.api.grid.element.css('height', height + 'px');
+
+                $timeout(() => this.api.core.handleWindowResize());
+            },
+            onRegisterApi(api) {
+                $animate.enabled(api.grid.element, false);
+
+                this.api = api;
+
+                this.rebuildColumns();
+
+                this.adjustHeight();
+            }
+        }});
+
+        Object.defineProperty(this, 'chartHistory', {value: []});
+    }
+
+    resultType() {
+        if (_.isNil(this.queryArgs))
+            return null;
+
+        if (!_.isEmpty(this.errMsg))
+            return 'error';
+
+        if (_.isEmpty(this.rows))
+            return 'empty';
+
+        return this.result === 'table' ? 'table' : 'chart';
+    }
+
+    nonRefresh() {
+        return _.isNil(this.rate) || _.isNil(this.rate.stopTime);
+    }
+
+    table() {
+        return this.result === 'table';
+    }
+
+    chart() {
+        return this.result !== 'table' && this.result !== 'none';
+    }
+
+    nonEmpty() {
+        return this.rows && this.rows.length > 0;
+    }
+
+    queryExecuted() {
+        return !_.isEmpty(this.meta);
+    }
+
+    scanExplain() {
+        return this.queryExecuted() && this.queryArgs.type !== 'QUERY';
+    }
+
+    timeLineSupported() {
+        return this.result !== 'pie';
+    }
+
+    chartColumnsConfigured() {
+        return !_.isEmpty(this.chartKeyCols) && !_.isEmpty(this.chartValCols);
+    }
+
+    chartTimeLineEnabled() {
+        return !_.isEmpty(this.chartKeyCols) && _.eq(this.chartKeyCols[0], TIME_LINE);
+    }
+}
+
+// Controller for SQL notebook screen.
+export default ['$rootScope', '$scope', '$http', '$q', '$timeout', '$interval', '$animate', '$location', '$anchorScroll', '$state', '$modal', '$popover', 'IgniteLoading', 'IgniteLegacyUtils', 'IgniteMessages', 'IgniteConfirm', 'IgniteAgentMonitor', 'IgniteChartColors', 'IgniteNotebook', 'IgniteScanFilterInput', 'uiGridExporterConstants',
+    function($root, $scope, $http, $q, $timeout, $interval, $animate, $location, $anchorScroll, $state, $modal, $popover, Loading, LegacyUtils, Messages, Confirm, agentMonitor, IgniteChartColors, Notebook, ScanFilterInput, uiGridExporterConstants) {
+        let stopTopology = null;
+
+        const _tryStopRefresh = function(paragraph) {
+            if (paragraph.rate && paragraph.rate.stopTime) {
+                $interval.cancel(paragraph.rate.stopTime);
+
+                delete paragraph.rate.stopTime;
+            }
+        };
+
+        const _stopTopologyRefresh = () => {
+            $interval.cancel(stopTopology);
+
+            if ($scope.notebook && $scope.notebook.paragraphs)
+                $scope.notebook.paragraphs.forEach((paragraph) => _tryStopRefresh(paragraph));
+        };
+
+        $scope.$on('$stateChangeStart', _stopTopologyRefresh);
+
+        $scope.caches = [];
+
+        $scope.pageSizes = [50, 100, 200, 400, 800, 1000];
+
+        $scope.timeLineSpans = ['1', '5', '10', '15', '30'];
+
+        $scope.aggregateFxs = ['FIRST', 'LAST', 'MIN', 'MAX', 'SUM', 'AVG', 'COUNT'];
+
+        $scope.modes = LegacyUtils.mkOptions(['PARTITIONED', 'REPLICATED', 'LOCAL']);
+
+        $scope.loadingText = $root.IgniteDemoMode ? 'Demo grid is starting. Please wait...' : 'Loading notebook screen...';
+
+        $scope.timeUnit = [
+            {value: 1000, label: 'seconds', short: 's'},
+            {value: 60000, label: 'minutes', short: 'm'},
+            {value: 3600000, label: 'hours', short: 'h'}
+        ];
+
+        $scope.exportDropdown = [
+            { text: 'Export all', click: 'exportCsvAll(paragraph)' }
+            // { 'text': 'Export all to CSV', 'click': 'exportCsvAll(paragraph)' },
+            // { 'text': 'Export all to PDF', 'click': 'exportPdfAll(paragraph)' }
+        ];
+
+        $scope.metadata = [];
+
+        $scope.metaFilter = '';
+
+        $scope.metaOptions = {
+            nodeChildren: 'children',
+            dirSelectable: true,
+            injectClasses: {
+                iExpanded: 'fa fa-minus-square-o',
+                iCollapsed: 'fa fa-plus-square-o'
+            }
+        };
+
+        $scope.maskCacheName = (cacheName) => _.isEmpty(cacheName) ? '<default>' : cacheName;
+
+        // We need max 1800 items to hold history for 30 mins in case of refresh every second.
+        const HISTORY_LENGTH = 1800;
+
+        const MAX_VAL_COLS = IgniteChartColors.length;
+
+        $anchorScroll.yOffset = 55;
+
+        $scope.chartColor = function(index) {
+            return {color: 'white', 'background-color': IgniteChartColors[index]};
+        };
+
+        function _chartNumber(arr, idx, dflt) {
+            if (idx >= 0 && arr && arr.length > idx && _.isNumber(arr[idx]))
+                return arr[idx];
+
+            return dflt;
+        }
+
+        function _min(rows, idx, dflt) {
+            let min = _chartNumber(rows[0], idx, dflt);
+
+            _.forEach(rows, (row) => {
+                const v = _chartNumber(row, idx, dflt);
+
+                if (v < min)
+                    min = v;
+            });
+
+            return min;
+        }
+
+        function _max(rows, idx, dflt) {
+            let max = _chartNumber(rows[0], idx, dflt);
+
+            _.forEach(rows, (row) => {
+                const v = _chartNumber(row, idx, dflt);
+
+                if (v > max)
+                    max = v;
+            });
+
+            return max;
+        }
+
+        function _sum(rows, idx) {
+            let sum = 0;
+
+            _.forEach(rows, (row) => sum += _chartNumber(row, idx, 0));
+
+            return sum;
+        }
+
+        function _aggregate(rows, aggFx, idx, dflt) {
+            const len = rows.length;
+
+            switch (aggFx) {
+                case 'FIRST':
+                    return _chartNumber(rows[0], idx, dflt);
+
+                case 'LAST':
+                    return _chartNumber(rows[len - 1], idx, dflt);
+
+                case 'MIN':
+                    return _min(rows, idx, dflt);
+
+                case 'MAX':
+                    return _max(rows, idx, dflt);
+
+                case 'SUM':
+                    return _sum(rows, idx);
+
+                case 'AVG':
+                    return len > 0 ? _sum(rows, idx) / len : 0;
+
+                case 'COUNT':
+                    return len;
+
+                default:
+            }
+
+            return 0;
+        }
+
+        function _chartLabel(arr, idx, dflt) {
+            if (arr && arr.length > idx && _.isString(arr[idx]))
+                return arr[idx];
+
+            return dflt;
+        }
+
+        function _chartDatum(paragraph) {
+            let datum = [];
+
+            if (paragraph.chartColumnsConfigured()) {
+                paragraph.chartValCols.forEach(function(valCol) {
+                    let index = 0;
+                    let values = [];
+                    const colIdx = valCol.value;
+
+                    if (paragraph.chartTimeLineEnabled()) {
+                        const aggFx = valCol.aggFx;
+                        const colLbl = valCol.label + ' [' + aggFx + ']';
+
+                        if (paragraph.charts && paragraph.charts.length === 1)
+                            datum = paragraph.charts[0].data;
+
+                        const chartData = _.find(datum, {series: valCol.label});
+
+                        const leftBound = new Date();
+                        leftBound.setMinutes(leftBound.getMinutes() - parseInt(paragraph.timeLineSpan, 10));
+
+                        if (chartData) {
+                            const lastItem = _.last(paragraph.chartHistory);
+
+                            values = chartData.values;
+
+                            values.push({
+                                x: lastItem.tm,
+                                y: _aggregate(lastItem.rows, aggFx, colIdx, index++)
+                            });
+
+                            while (values.length > 0 && values[0].x < leftBound)
+                                values.shift();
+                        }
+                        else {
+                            _.forEach(paragraph.chartHistory, (history) => {
+                                if (history.tm >= leftBound) {
+                                    values.push({
+                                        x: history.tm,
+                                        y: _aggregate(history.rows, aggFx, colIdx, index++)
+                                    });
+                                }
+                            });
+
+                            datum.push({series: valCol.label, key: colLbl, values});
+                        }
+                    }
+                    else {
+                        index = paragraph.total;
+
+                        values = _.map(paragraph.rows, function(row) {
+                            const xCol = paragraph.chartKeyCols[0].value;
+
+                            const v = {
+                                x: _chartNumber(row, xCol, index),
+                                xLbl: _chartLabel(row, xCol, null),
+                                y: _chartNumber(row, colIdx, index)
+                            };
+
+                            index++;
+
+                            return v;
+                        });
+
+                        datum.push({series: valCol.label, key: valCol.label, values});
+                    }
+                });
+            }
+
+            return datum;
+        }
+
+        function _xX(d) {
+            return d.x;
+        }
+
+        function _yY(d) {
+            return d.y;
+        }
+
+        function _xAxisTimeFormat(d) {
+            return d3.time.format('%X')(new Date(d));
+        }
+
+        const _intClasses = ['java.lang.Byte', 'java.lang.Integer', 'java.lang.Long', 'java.lang.Short'];
+
+        function _intType(cls) {
+            return _.includes(_intClasses, cls);
+        }
+
+        const _xAxisWithLabelFormat = function(paragraph) {
+            return function(d) {
+                const values = paragraph.charts[0].data[0].values;
+
+                const fmt = _intType(paragraph.chartKeyCols[0].type) ? 'd' : ',.2f';
+
+                const dx = values[d];
+
+                if (!dx)
+                    return d3.format(fmt)(d);
+
+                const lbl = dx.xLbl;
+
+                return lbl ? lbl : d3.format(fmt)(d);
+            };
+        };
+
+        function _xAxisLabel(paragraph) {
+            return _.isEmpty(paragraph.chartKeyCols) ? 'X' : paragraph.chartKeyCols[0].label;
+        }
+
+        const _yAxisFormat = function(d) {
+            const fmt = d < 1000 ? ',.2f' : '.3s';
+
+            return d3.format(fmt)(d);
+        };
+
+        function _updateCharts(paragraph) {
+            $timeout(() => _.forEach(paragraph.charts, (chart) => chart.api.update()), 100);
+        }
+
+        function _updateChartsWithData(paragraph, newDatum) {
+            $timeout(() => {
+                if (!paragraph.chartTimeLineEnabled()) {
+                    const chartDatum = paragraph.charts[0].data;
+
+                    chartDatum.length = 0;
+
+                    _.forEach(newDatum, (series) => chartDatum.push(series));
+                }
+
+                paragraph.charts[0].api.update();
+            });
+        }
+
+        function _yAxisLabel(paragraph) {
+            const cols = paragraph.chartValCols;
+
+            const tml = paragraph.chartTimeLineEnabled();
+
+            return _.isEmpty(cols) ? 'Y' : _.map(cols, function(col) {
+                let lbl = col.label;
+
+                if (tml)
+                    lbl += ' [' + col.aggFx + ']';
+
+                return lbl;
+            }).join(', ');
+        }
+
+        function _barChart(paragraph) {
+            const datum = _chartDatum(paragraph);
+
+            if (_.isEmpty(paragraph.charts)) {
+                const stacked = paragraph.chartsOptions && paragraph.chartsOptions.barChart
+                    ? paragraph.chartsOptions.barChart.stacked
+                    : true;
+
+                const options = {
+                    chart: {
+                        type: 'multiBarChart',
+                        height: 400,
+                        margin: {left: 70},
+                        duration: 0,
+                        x: _xX,
+                        y: _yY,
+                        xAxis: {
+                            axisLabel: _xAxisLabel(paragraph),
+                            tickFormat: paragraph.chartTimeLineEnabled() ? _xAxisTimeFormat : _xAxisWithLabelFormat(paragraph),
+                            showMaxMin: false
+                        },
+                        yAxis: {
+                            axisLabel: _yAxisLabel(paragraph),
+                            tickFormat: _yAxisFormat
+                        },
+                        color: IgniteChartColors,
+                        stacked,
+                        showControls: true,
+                        legend: {
+                            vers: 'furious',
+                            margin: {right: -25}
+                        }
+                    }
+                };
+
+                paragraph.charts = [{options, data: datum}];
+
+                _updateCharts(paragraph);
+            }
+            else
+                _updateChartsWithData(paragraph, datum);
+        }
+
+        function _pieChartDatum(paragraph) {
+            const datum = [];
+
+            if (paragraph.chartColumnsConfigured() && !paragraph.chartTimeLineEnabled()) {
+                paragraph.chartValCols.forEach(function(valCol) {
+                    let index = paragraph.total;
+
+                    const values = _.map(paragraph.rows, (row) => {
+                        const xCol = paragraph.chartKeyCols[0].value;
+
+                        const v = {
+                            x: xCol < 0 ? index : row[xCol],
+                            y: _chartNumber(row, valCol.value, index)
+                        };
+
+                        // Workaround for known problem with zero values on Pie chart.
+                        if (v.y === 0)
+                            v.y = 0.0001;
+
+                        index++;
+
+                        return v;
+                    });
+
+                    datum.push({series: paragraph.chartKeyCols[0].label, key: valCol.label, values});
+                });
+            }
+
+            return datum;
+        }
+
+        function _pieChart(paragraph) {
+            let datum = _pieChartDatum(paragraph);
+
+            if (datum.length === 0)
+                datum = [{values: []}];
+
+            paragraph.charts = _.map(datum, function(data) {
+                return {
+                    options: {
+                        chart: {
+                            type: 'pieChart',
+                            height: 400,
+                            duration: 0,
+                            x: _xX,
+                            y: _yY,
+                            showLabels: true,
+                            labelThreshold: 0.05,
+                            labelType: 'percent',
+                            donut: true,
+                            donutRatio: 0.35,
+                            legend: {
+                                vers: 'furious',
+                                margin: {
+                                    right: -25
+                                }
+                            }
+                        },
+                        title: {
+                            enable: true,
+                            text: data.key
+                        }
+                    },
+                    data: data.values
+                };
+            });
+
+            _updateCharts(paragraph);
+        }
+
+        function _lineChart(paragraph) {
+            const datum = _chartDatum(paragraph);
+
+            if (_.isEmpty(paragraph.charts)) {
+                const options = {
+                    chart: {
+                        type: 'lineChart',
+                        height: 400,
+                        margin: { left: 70 },
+                        duration: 0,
+                        x: _xX,
+                        y: _yY,
+                        xAxis: {
+                            axisLabel: _xAxisLabel(paragraph),
+                            tickFormat: paragraph.chartTimeLineEnabled() ? _xAxisTimeFormat : _xAxisWithLabelFormat(paragraph),
+                            showMaxMin: false
+                        },
+                        yAxis: {
+                            axisLabel: _yAxisLabel(paragraph),
+                            tickFormat: _yAxisFormat
+                        },
+                        color: IgniteChartColors,
+                        useInteractiveGuideline: true,
+                        legend: {
+                            vers: 'furious',
+                            margin: {
+                                right: -25
+                            }
+                        }
+                    }
+                };
+
+                paragraph.charts = [{options, data: datum}];
+
+                _updateCharts(paragraph);
+            }
+            else
+                _updateChartsWithData(paragraph, datum);
+        }
+
+        function _areaChart(paragraph) {
+            const datum = _chartDatum(paragraph);
+
+            if (_.isEmpty(paragraph.charts)) {
+                const style = paragraph.chartsOptions && paragraph.chartsOptions.areaChart
+                    ? paragraph.chartsOptions.areaChart.style
+                    : 'stack';
+
+                const options = {
+                    chart: {
+                        type: 'stackedAreaChart',
+                        height: 400,
+                        margin: {left: 70},
+                        duration: 0,
+                        x: _xX,
+                        y: _yY,
+                        xAxis: {
+                            axisLabel: _xAxisLabel(paragraph),
+                            tickFormat: paragraph.chartTimeLineEnabled() ? _xAxisTimeFormat : _xAxisWithLabelFormat(paragraph),
+                            showMaxMin: false
+                        },
+                        yAxis: {
+                            axisLabel: _yAxisLabel(paragraph),
+                            tickFormat: _yAxisFormat
+                        },
+                        color: IgniteChartColors,
+                        style,
+                        legend: {
+                            vers: 'furious',
+                            margin: {right: -25}
+                        }
+                    }
+                };
+
+                paragraph.charts = [{options, data: datum}];
+
+                _updateCharts(paragraph);
+            }
+            else
+                _updateChartsWithData(paragraph, datum);
+        }
+
+        function _chartApplySettings(paragraph, resetCharts) {
+            if (resetCharts)
+                paragraph.charts = [];
+
+            if (paragraph.chart() && paragraph.nonEmpty()) {
+                switch (paragraph.result) {
+                    case 'bar':
+                        _barChart(paragraph);
+                        break;
+
+                    case 'pie':
+                        _pieChart(paragraph);
+                        break;
+
+                    case 'line':
+                        _lineChart(paragraph);
+                        break;
+
+                    case 'area':
+                        _areaChart(paragraph);
+                        break;
+
+                    default:
+                }
+            }
+        }
+
+        $scope.chartRemoveKeyColumn = function(paragraph, index) {
+            paragraph.chartKeyCols.splice(index, 1);
+
+            _chartApplySettings(paragraph, true);
+        };
+
+        $scope.chartRemoveValColumn = function(paragraph, index) {
+            paragraph.chartValCols.splice(index, 1);
+
+            _chartApplySettings(paragraph, true);
+        };
+
+        $scope.chartAcceptKeyColumn = function(paragraph, item) {
+            const accepted = _.findIndex(paragraph.chartKeyCols, item) < 0;
+
+            if (accepted) {
+                paragraph.chartKeyCols = [item];
+
+                _chartApplySettings(paragraph, true);
+            }
+
+            return false;
+        };
+
+        const _numberClasses = ['java.math.BigDecimal', 'java.lang.Byte', 'java.lang.Double',
+            'java.lang.Float', 'java.lang.Integer', 'java.lang.Long', 'java.lang.Short'];
+
+        const _numberType = function(cls) {
+            return _.includes(_numberClasses, cls);
+        };
+
+        $scope.chartAcceptValColumn = function(paragraph, item) {
+            const valCols = paragraph.chartValCols;
+
+            const accepted = _.findIndex(valCols, item) < 0 && item.value >= 0 && _numberType(item.type);
+
+            if (accepted) {
+                if (valCols.length === MAX_VAL_COLS - 1)
+                    valCols.shift();
+
+                valCols.push(item);
+
+                _chartApplySettings(paragraph, true);
+            }
+
+            return false;
+        };
+
+        $scope.scrollParagraphs = [];
+
+        $scope.rebuildScrollParagraphs = function() {
+            $scope.scrollParagraphs = $scope.notebook.paragraphs.map(function(paragraph) {
+                return {
+                    text: paragraph.name,
+                    click: 'scrollToParagraph("' + paragraph.id + '")'
+                };
+            });
+        };
+
+        $scope.scrollToParagraph = (id) => {
+            const idx = _.findIndex($scope.notebook.paragraphs, {id});
+
+            if (idx >= 0) {
+                if (!_.includes($scope.notebook.expandedParagraphs, idx))
+                    $scope.notebook.expandedParagraphs.push(idx);
+
+                setTimeout(function() {
+                    $scope.notebook.paragraphs[idx].ace.focus();
+                });
+            }
+
+            $location.hash(id);
+
+            $anchorScroll();
+        };
+
+        const _hideColumn = (col) => col.fieldName !== '_KEY' && col.fieldName !== '_VAL';
+
+        const _allColumn = () => true;
+
+        $scope.aceInit = function(paragraph) {
+            return function(editor) {
+                editor.setAutoScrollEditorIntoView(true);
+                editor.$blockScrolling = Infinity;
+
+                const renderer = editor.renderer;
+
+                renderer.setHighlightGutterLine(false);
+                renderer.setShowPrintMargin(false);
+                renderer.setOption('fontFamily', 'monospace');
+                renderer.setOption('fontSize', '14px');
+                renderer.setOption('minLines', '5');
+                renderer.setOption('maxLines', '15');
+
+                editor.setTheme('ace/theme/chrome');
+
+                Object.defineProperty(paragraph, 'ace', { value: editor });
+            };
+        };
+
+        /**
+         * Update caches list.
+         * @private
+         */
+        const _refreshFn = () =>
+            agentMonitor.topology()
+                .then((clusters) => {
+                    $scope.caches = _.sortBy(_.reduce(clusters, (items, cluster) => {
+                        _.forEach(cluster.caches, (cache) => {
+                            let item = _.find(items, {name: cache.name});
+
+                            if (_.isNil(item)) {
+                                cache.label = $scope.maskCacheName(cache.name);
+
+                                cache.nodeIds = [];
+
+                                items.push(item = cache);
+                            }
+
+                            item.nodeIds.push(cluster.nodeId);
+                        });
+
+                        return items;
+                    }, []), 'label');
+
+                    if (_.isEmpty($scope.caches))
+                        return;
+
+                    // Reset to first cache in case of stopped selected.
+                    const cacheNames = _.map($scope.caches, (cache) => cache.name);
+
+                    _.forEach($scope.notebook.paragraphs, (paragraph) => {
+                        if (!_.includes(cacheNames, paragraph.cacheName))
+                            paragraph.cacheName = _.head(cacheNames);
+                    });
+                })
+                .then(() => agentMonitor.checkModal())
+                .catch((err) => agentMonitor.showNodeError(err));
+
+        const _startWatch = () =>
+            agentMonitor.startWatch({
+                state: 'base.configuration.clusters',
+                text: 'Back to Configuration',
+                goal: 'execute sql statements',
+                onDisconnect: () => {
+                    _stopTopologyRefresh();
+
+                    _startWatch();
+                }
+            })
+                .then(() => Loading.start('sqlLoading'))
+                .then(_refreshFn)
+                .then(() => Loading.finish('sqlLoading'))
+                .then(() => {
+                    $root.IgniteDemoMode && _.forEach($scope.notebook.paragraphs, $scope.execute);
+
+                    stopTopology = $interval(_refreshFn, 5000, 0, false);
+                });
+
+        Notebook.find($state.params.noteId)
+            .then((notebook) => {
+                $scope.notebook = _.cloneDeep(notebook);
+
+                $scope.notebook_name = $scope.notebook.name;
+
+                if (!$scope.notebook.expandedParagraphs)
+                    $scope.notebook.expandedParagraphs = [];
+
+                if (!$scope.notebook.paragraphs)
+                    $scope.notebook.paragraphs = [];
+
+                $scope.notebook.paragraphs = _.map($scope.notebook.paragraphs,
+                    (paragraph) => new Paragraph($animate, $timeout, paragraph));
+
+                if (_.isEmpty($scope.notebook.paragraphs))
+                    $scope.addParagraph();
+                else
+                    $scope.rebuildScrollParagraphs();
+            })
+            .then(_startWatch)
+            .catch(() => {
+                $scope.notebookLoadFailed = true;
+
+                Loading.finish('sqlLoading');
+            });
+
+        $scope.renameNotebook = (name) => {
+            if (!name)
+                return;
+
+            if ($scope.notebook.name !== name) {
+                const prevName = $scope.notebook.name;
+
+                $scope.notebook.name = name;
+
+                Notebook.save($scope.notebook)
+                    .then(() => $scope.notebook.edit = false)
+                    .catch((err) => {
+                        $scope.notebook.name = prevName;
+
+                        Messages.showError(err);
+                    });
+            }
+            else
+                $scope.notebook.edit = false;
+        };
+
+        $scope.removeNotebook = (notebook) => Notebook.remove(notebook);
+
+        $scope.renameParagraph = function(paragraph, newName) {
+            if (!newName)
+                return;
+
+            if (paragraph.name !== newName) {
+                paragraph.name = newName;
+
+                $scope.rebuildScrollParagraphs();
+
+                Notebook.save($scope.notebook)
+                    .then(() => paragraph.edit = false)
+                    .catch(Messages.showError);
+            }
+            else
+                paragraph.edit = false;
+        };
+
+        $scope.addParagraph = function() {
+            const sz = $scope.notebook.paragraphs.length;
+
+            const paragraph = new Paragraph($animate, $timeout, {
+                name: 'Query' + (sz === 0 ? '' : sz),
+                query: '',
+                pageSize: $scope.pageSizes[0],
+                timeLineSpan: $scope.timeLineSpans[0],
+                result: 'none',
+                rate: {
+                    value: 1,
+                    unit: 60000,
+                    installed: false
+                }
+            });
+
+            if ($scope.caches && $scope.caches.length > 0)
+                paragraph.cacheName = $scope.caches[0].name;
+
+            $scope.notebook.paragraphs.push(paragraph);
+
+            $scope.notebook.expandedParagraphs.push(sz);
+
+            $scope.rebuildScrollParagraphs();
+
+            $location.hash(paragraph.id);
+
+            $timeout(() => {
+                $anchorScroll();
+
+                paragraph.ace.focus();
+            });
+        };
+
+        function _saveChartSettings(paragraph) {
+            if (!_.isEmpty(paragraph.charts)) {
+                const chart = paragraph.charts[0].api.getScope().chart;
+
+                if (!LegacyUtils.isDefined(paragraph.chartsOptions))
+                    paragraph.chartsOptions = {barChart: {stacked: true}, areaChart: {style: 'stack'}};
+
+                switch (paragraph.result) {
+                    case 'bar':
+                        paragraph.chartsOptions.barChart.stacked = chart.stacked();
+
+                        break;
+
+                    case 'area':
+                        paragraph.chartsOptions.areaChart.style = chart.style();
+
+                        break;
+
+                    default:
+                }
+            }
+        }
+
+        $scope.setResult = function(paragraph, new_result) {
+            if (paragraph.result === new_result)
+                return;
+
+            _saveChartSettings(paragraph);
+
+            paragraph.result = new_result;
+
+            if (paragraph.chart())
+                _chartApplySettings(paragraph, true);
+        };
+
+        $scope.resultEq = function(paragraph, result) {
+            return (paragraph.result === result);
+        };
+
+        $scope.removeParagraph = function(paragraph) {
+            Confirm.confirm('Are you sure you want to remove: "' + paragraph.name + '"?')
+                .then(function() {
+                    $scope.stopRefresh(paragraph);
+
+                    const paragraph_idx = _.findIndex($scope.notebook.paragraphs, function(item) {
+                        return paragraph === item;
+                    });
+
+                    const panel_idx = _.findIndex($scope.expandedParagraphs, function(item) {
+                        return paragraph_idx === item;
+                    });
+
+                    if (panel_idx >= 0)
+                        $scope.expandedParagraphs.splice(panel_idx, 1);
+
+                    $scope.notebook.paragraphs.splice(paragraph_idx, 1);
+
+                    $scope.rebuildScrollParagraphs();
+
+                    Notebook.save($scope.notebook)
+                        .catch(Messages.showError);
+                });
+        };
+
+        $scope.paragraphExpanded = function(paragraph) {
+            const paragraph_idx = _.findIndex($scope.notebook.paragraphs, function(item) {
+                return paragraph === item;
+            });
+
+            const panel_idx = _.findIndex($scope.notebook.expandedParagraphs, function(item) {
+                return paragraph_idx === item;
+            });
+
+            return panel_idx >= 0;
+        };
+
+        const _columnFilter = function(paragraph) {
+            return paragraph.disabledSystemColumns || paragraph.systemColumns ? _allColumn : _hideColumn;
+        };
+
+        const _notObjectType = function(cls) {
+            return LegacyUtils.isJavaBuiltInClass(cls);
+        };
+
+        function _retainColumns(allCols, curCols, acceptableType, xAxis, unwantedCols) {
+            const retainedCols = [];
+
+            const availableCols = xAxis ? allCols : _.filter(allCols, function(col) {
+                return col.value >= 0;
+            });
+
+            if (availableCols.length > 0) {
+                curCols.forEach(function(curCol) {
+                    const col = _.find(availableCols, {label: curCol.label});
+
+                    if (col && acceptableType(col.type)) {
+                        col.aggFx = curCol.aggFx;
+
+                        retainedCols.push(col);
+                    }
+                });
+
+                // If nothing was restored, add first acceptable column.
+                if (_.isEmpty(retainedCols)) {
+                    let col;
+
+                    if (unwantedCols)
+                        col = _.find(availableCols, (avCol) => !_.find(unwantedCols, {label: avCol.label}) && acceptableType(avCol.type));
+
+                    if (!col)
+                        col = _.find(availableCols, (avCol) => acceptableType(avCol.type));
+
+                    if (col)
+                        retainedCols.push(col);
+                }
+            }
+
+            return retainedCols;
+        }
+
+        const _rebuildColumns = function(paragraph) {
+            _.forEach(_.groupBy(paragraph.meta, 'fieldName'), function(colsByName, fieldName) {
+                const colsByTypes = _.groupBy(colsByName, 'typeName');
+
+                const needType = _.keys(colsByTypes).length > 1;
+
+                _.forEach(colsByTypes, function(colsByType, typeName) {
+                    _.forEach(colsByType, function(col, ix) {
+                        col.fieldName = (needType && !LegacyUtils.isEmptyString(typeName) ? typeName + '.' : '') + fieldName + (ix > 0 ? ix : '');
+                    });
+                });
+            });
+
+            paragraph.gridOptions.rebuildColumns();
+
+            paragraph.chartColumns = _.reduce(paragraph.meta, (acc, col, idx) => {
+                if (paragraph.columnFilter(col) && _notObjectType(col.fieldTypeName)) {
+                    acc.push({
+                        label: col.fieldName,
+                        type: col.fieldTypeName,
+                        aggFx: $scope.aggregateFxs[0],
+                        value: idx.toString()
+                    });
+                }
+
+                return acc;
+            }, []);
+
+            if (paragraph.chartColumns.length > 0) {
+                paragraph.chartColumns.push(TIME_LINE);
+                paragraph.chartColumns.push(ROW_IDX);
+            }
+
+            // We could accept onl not object columns for X axis.
+            paragraph.chartKeyCols = _retainColumns(paragraph.chartColumns, paragraph.chartKeyCols, _notObjectType, true);
+
+            // We could accept only numeric columns for Y axis.
+            paragraph.chartValCols = _retainColumns(paragraph.chartColumns, paragraph.chartValCols, _numberType, false, paragraph.chartKeyCols);
+        };
+
+        $scope.toggleSystemColumns = function(paragraph) {
+            if (paragraph.disabledSystemColumns)
+                return;
+
+            paragraph.systemColumns = !paragraph.systemColumns;
+
+            paragraph.columnFilter = _columnFilter(paragraph);
+
+            paragraph.chartColumns = [];
+
+            _rebuildColumns(paragraph);
+        };
+
+        const _showLoading = (paragraph, enable) => paragraph.loading = enable;
+
+        /**
+         * @param {Object} paragraph Query
+         * @param {{columns: Array, rows: Array, responseNodeId: String, queryId: int, hasMore: Boolean}} res Query results.
+         * @private
+         */
+        const _processQueryResult = (paragraph, res) => {
+            const prevKeyCols = paragraph.chartKeyCols;
+            const prevValCols = paragraph.chartValCols;
+
+            if (!_.eq(paragraph.meta, res.columns)) {
+                paragraph.meta = [];
+
+                paragraph.chartColumns = [];
+
+                if (!LegacyUtils.isDefined(paragraph.chartKeyCols))
+                    paragraph.chartKeyCols = [];
+
+                if (!LegacyUtils.isDefined(paragraph.chartValCols))
+                    paragraph.chartValCols = [];
+
+                if (res.columns.length <= 2) {
+                    const _key = _.find(res.columns, {fieldName: '_KEY'});
+                    const _val = _.find(res.columns, {fieldName: '_VAL'});
+
+                    paragraph.disabledSystemColumns = (res.columns.length === 2 && _key && _val) ||
+                        (res.columns.length === 1 && (_key || _val));
+                }
+
+                paragraph.columnFilter = _columnFilter(paragraph);
+
+                paragraph.meta = res.columns;
+
+                _rebuildColumns(paragraph);
+            }
+
+            paragraph.page = 1;
+
+            paragraph.total = 0;
+
+            paragraph.duration = res.duration;
+
+            paragraph.queryId = res.hasMore ? res.queryId : null;
+
+            paragraph.resNodeId = res.responseNodeId;
+
+            delete paragraph.errMsg;
+
+            // Prepare explain results for display in table.
+            if (paragraph.queryArgs.query && paragraph.queryArgs.query.startsWith('EXPLAIN') && res.rows) {
+                paragraph.rows = [];
+
+                res.rows.forEach((row, i) => {
+                    const line = res.rows.length - 1 === i ? row[0] : row[0] + '\n';
+
+                    line.replace(/\"/g, '').split('\n').forEach((ln) => paragraph.rows.push([ln]));
+                });
+            }
+            else
+                paragraph.rows = res.rows;
+
+            paragraph.gridOptions.adjustHeight(paragraph.rows.length);
+
+            const chartHistory = paragraph.chartHistory;
+
+            // Clear history on query change.
+            const queryChanged = paragraph.prevQuery !== paragraph.query;
+
+            if (queryChanged) {
+                paragraph.prevQuery = paragraph.query;
+
+                chartHistory.length = 0;
+
+                _.forEach(paragraph.charts, (chart) => chart.data.length = 0);
+            }
+
+            // Add results to history.
+            chartHistory.push({tm: new Date(), rows: paragraph.rows});
+
+            // Keep history size no more than max length.
+            while (chartHistory.length > HISTORY_LENGTH)
+                chartHistory.shift();
+
+            _showLoading(paragraph, false);
+
+            if (_.isNil(paragraph.result) || paragraph.result === 'none' || paragraph.scanExplain())
+                paragraph.result = 'table';
+            else if (paragraph.chart()) {
+                let resetCharts = queryChanged;
+
+                if (!resetCharts) {
+                    const curKeyCols = paragraph.chartKeyCols;
+                    const curValCols = paragraph.chartValCols;
+
+                    resetCharts = !prevKeyCols || !prevValCols ||
+                        prevKeyCols.length !== curKeyCols.length ||
+                        prevValCols.length !== curValCols.length;
+                }
+
+                _chartApplySettings(paragraph, resetCharts);
+            }
+        };
+
+        const _closeOldQuery = (paragraph) => {
+            const queryId = paragraph.queryArgs && paragraph.queryArgs.queryId;
+
+            return queryId ? agentMonitor.queryClose(queryId) : $q.when();
+        };
+
+        const cacheNode = (name) => {
+            const cache = _.find($scope.caches, {name});
+
+            return cache.nodeIds[_.random(0, cache.nodeIds.length - 1)];
+        };
+
+        const _executeRefresh = (paragraph) => {
+            const args = paragraph.queryArgs;
+
+            agentMonitor.awaitAgent()
+                .then(() => _closeOldQuery(paragraph))
+                .then(() => agentMonitor.query(cacheNode(args.cacheName), args.cacheName, args.query, false, args.pageSize))
+                .then(_processQueryResult.bind(this, paragraph))
+                .catch((err) => paragraph.errMsg = err.message);
+        };
+
+        const _tryStartRefresh = function(paragraph) {
+            _tryStopRefresh(paragraph);
+
+            if (paragraph.rate && paragraph.rate.installed && paragraph.queryArgs) {
+                $scope.chartAcceptKeyColumn(paragraph, TIME_LINE);
+
+                _executeRefresh(paragraph);
+
+                const delay = paragraph.rate.value * paragraph.rate.unit;
+
+                paragraph.rate.stopTime = $interval(_executeRefresh, delay, 0, false, paragraph);
+            }
+        };
+
+        $scope.execute = (paragraph) => {
+            if (!$scope.actionAvailable(paragraph, true))
+                return;
+
+            Notebook.save($scope.notebook)
+                .catch(Messages.showError);
+
+            paragraph.prevQuery = paragraph.queryArgs ? paragraph.queryArgs.query : paragraph.query;
+
+            _showLoading(paragraph, true);
+
+            _closeOldQuery(paragraph)
+                .then(() => {
+                    const args = paragraph.queryArgs = {
+                        cacheName: paragraph.cacheName,
+                        pageSize: paragraph.pageSize,
+                        query: paragraph.query,
+                        type: 'QUERY'
+                    };
+
+                    return agentMonitor.query(cacheNode(paragraph.cacheName), args.cacheName, args.query, false, args.pageSize);
+                })
+                .then((res) => {
+                    _processQueryResult(paragraph, res);
+
+                    _tryStartRefresh(paragraph);
+                })
+                .catch((err) => {
+                    paragraph.errMsg = err.message;
+
+                    _showLoading(paragraph, false);
+
+                    $scope.stopRefresh(paragraph);
+                })
+                .then(() => paragraph.ace.focus());
+        };
+
+        const _cancelRefresh = (paragraph) => {
+            if (paragraph.rate && paragraph.rate.stopTime) {
+                delete paragraph.queryArgs;
+
+                paragraph.rate.installed = false;
+
+                $interval.cancel(paragraph.rate.stopTime);
+
+                delete paragraph.rate.stopTime;
+            }
+        };
+
+        $scope.explain = (paragraph) => {
+            if (!$scope.actionAvailable(paragraph, true))
+                return;
+
+            Notebook.save($scope.notebook)
+                .catch(Messages.showError);
+
+            _cancelRefresh(paragraph);
+
+            _showLoading(paragraph, true);
+
+            _closeOldQuery(paragraph)
+                .then(() => {
+                    const args = paragraph.queryArgs = {
+                        cacheName: paragraph.cacheName,
+                        pageSize: paragraph.pageSize,
+                        query: 'EXPLAIN ' + paragraph.query,
+                        type: 'EXPLAIN'
+                    };
+
+                    return agentMonitor.query(cacheNode(paragraph.cacheName), args.cacheName, args.query, false, args.pageSize);
+                })
+                .then(_processQueryResult.bind(this, paragraph))
+                .catch((err) => {
+                    paragraph.errMsg = err.message;
+
+                    _showLoading(paragraph, false);
+                })
+                .then(() => paragraph.ace.focus());
+        };
+
+        $scope.scan = (paragraph, query = null) => {
+            if (!$scope.actionAvailable(paragraph, false))
+                return;
+
+            Notebook.save($scope.notebook)
+                .catch(Messages.showError);
+
+            _cancelRefresh(paragraph);
+
+            _showLoading(paragraph, true);
+
+            _closeOldQuery(paragraph)
+                .then(() => {
+                    const args = paragraph.queryArgs = {
+                        cacheName: paragraph.cacheName,
+                        pageSize: paragraph.pageSize,
+                        query,
+                        type: 'SCAN'
+                    };
+
+                    return agentMonitor.query(cacheNode(paragraph.cacheName), args.cacheName, query, false, args.pageSize);
+                })
+                .then(_processQueryResult.bind(this, paragraph))
+                .catch((err) => {
+                    paragraph.errMsg = err.message;
+
+                    _showLoading(paragraph, false);
+                })
+                .then(() => paragraph.ace.focus());
+        };
+
+        $scope.scanWithFilter = (paragraph) => {
+            if (!$scope.actionAvailable(paragraph, false))
+                return;
+
+            ScanFilterInput.open()
+                .then(({filter, caseSensitive}) => {
+                    const prefix = caseSensitive ? SCAN_CACHE_WITH_FILTER_CASE_SENSITIVE : SCAN_CACHE_WITH_FILTER;
+
+                    $scope.scan(paragraph, `${prefix}${filter}`);
+                });
+        };
+
+        function _updatePieChartsWithData(paragraph, newDatum) {
+            $timeout(() => {
+                _.forEach(paragraph.charts, function(chart) {
+                    const chartDatum = chart.data;
+
+                    chartDatum.length = 0;
+
+                    _.forEach(newDatum, function(series) {
+                        if (chart.options.title.text === series.key)
+                            _.forEach(series.values, (v) => chartDatum.push(v));
+                    });
+                });
+
+                _.forEach(paragraph.charts, (chart) => chart.api.update());
+            });
+        }
+
+        $scope.nextPage = (paragraph) => {
+            _showLoading(paragraph, true);
+
+            paragraph.queryArgs.pageSize = paragraph.pageSize;
+
+            agentMonitor.next(paragraph.resNodeId, paragraph.queryId, paragraph.pageSize)
+                .then((res) => {
+                    paragraph.page++;
+
+                    paragraph.total += paragraph.rows.length;
+
+                    paragraph.duration = res.duration;
+
+                    paragraph.rows = res.rows;
+
+                    if (paragraph.chart()) {
+                        if (paragraph.result === 'pie')
+                            _updatePieChartsWithData(paragraph, _pieChartDatum(paragraph));
+                        else
+                            _updateChartsWithData(paragraph, _chartDatum(paragraph));
+                    }
+
+                    paragraph.gridOptions.adjustHeight(paragraph.rows.length);
+
+                    _showLoading(paragraph, false);
+
+                    if (!res.hasMore)
+                        delete paragraph.queryId;
+                })
+                .catch((err) => {
+                    paragraph.errMsg = err.message;
+
+                    _showLoading(paragraph, false);
+                })
+                .then(() => paragraph.ace.focus());
+        };
+
+        const _export = (fileName, columnFilter, meta, rows) => {
+            let csvContent = '';
+
+            const cols = [];
+            const excludedCols = [];
+
+            if (meta) {
+                _.forEach(meta, (col, idx) => {
+                    if (columnFilter(col))
+                        cols.push(_fullColName(col));
+                    else
+                        excludedCols.push(idx);
+                });
+
+                csvContent += cols.join(';') + '\n';
+            }
+
+            _.forEach(rows, (row) => {
+                cols.length = 0;
+
+                if (Array.isArray(row)) {
+                    _.forEach(row, (elem, idx) => {
+                        if (_.includes(excludedCols, idx))
+                            return;
+
+                        cols.push(_.isUndefined(elem) ? '' : JSON.stringify(elem));
+                    });
+                }
+                else {
+                    _.forEach(meta, (col) => {
+                        if (columnFilter(col)) {
+                            const elem = row[col.fieldName];
+
+                            cols.push(_.isUndefined(elem) ? '' : JSON.stringify(elem));
+                        }
+                    });
+                }
+
+                csvContent += cols.join(';') + '\n';
+            });
+
+            LegacyUtils.download('application/octet-stream;charset=utf-8', fileName, escape(csvContent));
+        };
+
+        $scope.exportCsv = function(paragraph) {
+            _export(paragraph.name + '.csv', paragraph.columnFilter, paragraph.meta, paragraph.rows);
+
+            // paragraph.gridOptions.api.exporter.csvExport(uiGridExporterConstants.ALL, uiGridExporterConstants.VISIBLE);
+        };
+
+        $scope.exportPdf = function(paragraph) {
+            paragraph.gridOptions.api.exporter.pdfExport(uiGridExporterConstants.ALL, uiGridExporterConstants.VISIBLE);
+        };
+
+        $scope.exportCsvAll = function(paragraph) {
+            const args = paragraph.queryArgs;
+
+            agentMonitor.queryGetAll(cacheNode(args.cacheName), args.cacheName, args.query, false)
+                .then((res) => _export(paragraph.name + '-all.csv', paragraph.columnFilter, res.columns, res.rows))
+                .catch(Messages.showError)
+                .then(() => paragraph.ace.focus());
+        };
+
+        // $scope.exportPdfAll = function(paragraph) {
+        //    $http.post('/api/v1/agent/query/getAll', {query: paragraph.query, cacheName: paragraph.cacheName})
+        //        .success(function(item) {
+        //            _export(paragraph.name + '-all.csv', item.meta, item.rows);
+        //    })
+        //    .error(Messages.showError);
+        // };
+
+        $scope.rateAsString = function(paragraph) {
+            if (paragraph.rate && paragraph.rate.installed) {
+                const idx = _.findIndex($scope.timeUnit, function(unit) {
+                    return unit.value === paragraph.rate.unit;
+                });
+
+                if (idx >= 0)
+                    return ' ' + paragraph.rate.value + $scope.timeUnit[idx].short;
+
+                paragraph.rate.installed = false;
+            }
+
+            return '';
+        };
+
+        $scope.startRefresh = function(paragraph, value, unit) {
+            paragraph.rate.value = value;
+            paragraph.rate.unit = unit;
+            paragraph.rate.installed = true;
+
+            if (paragraph.queryExecuted())
+                _tryStartRefresh(paragraph);
+        };
+
+        $scope.stopRefresh = function(paragraph) {
+            paragraph.rate.installed = false;
+
+            _tryStopRefresh(paragraph);
+        };
+
+        $scope.paragraphTimeSpanVisible = function(paragraph) {
+            return paragraph.timeLineSupported() && paragraph.chartTimeLineEnabled();
+        };
+
+        $scope.paragraphTimeLineSpan = function(paragraph) {
+            if (paragraph && paragraph.timeLineSpan)
+                return paragraph.timeLineSpan.toString();
+
+            return '1';
+        };
+
+        $scope.applyChartSettings = function(paragraph) {
+            _chartApplySettings(paragraph, true);
+        };
+
+        $scope.actionAvailable = function(paragraph, needQuery) {
+            return $scope.caches.length > 0 && (!needQuery || paragraph.query) && !paragraph.loading;
+        };
+
+        $scope.actionTooltip = function(paragraph, action, needQuery) {
+            if ($scope.actionAvailable(paragraph, needQuery))
+                return;
+
+            if (paragraph.loading)
+                return 'Waiting for server response';
+
+            return 'To ' + action + ' query select cache' + (needQuery ? ' and input query' : '');
+        };
+
+        $scope.clickableMetadata = function(node) {
+            return node.type.slice(0, 5) !== 'index';
+        };
+
+        $scope.dblclickMetadata = function(paragraph, node) {
+            paragraph.ace.insert(node.name);
+
+            setTimeout(function() {
+                paragraph.ace.focus();
+            }, 1);
+        };
+
+        $scope.importMetadata = function() {
+            Loading.start('loadingCacheMetadata');
+
+            $scope.metadata = [];
+
+            agentMonitor.metadata()
+                .then((metadata) => {
+                    $scope.metadata = _.sortBy(_.filter(metadata, (meta) => {
+                        const cache = _.find($scope.caches, { name: meta.cacheName });
+
+                        if (cache) {
+                            meta.name = (cache.sqlSchema || '"' + meta.cacheName + '"') + '.' + meta.typeName;
+                            meta.displayName = (cache.sqlSchema || meta.maskedName) + '.' + meta.typeName;
+
+                            if (cache.sqlSchema)
+                                meta.children.unshift({type: 'plain', name: 'cacheName: ' + meta.maskedName, maskedName: meta.maskedName});
+
+                            meta.children.unshift({type: 'plain', name: 'mode: ' + cache.mode, maskedName: meta.maskedName});
+                        }
+
+                        return cache;
+                    }), 'name');
+                })
+                .catch(Messages.showError)
+                .then(() => Loading.finish('loadingCacheMetadata'));
+        };
+
+        $scope.showResultQuery = function(paragraph) {
+            if (!_.isNil(paragraph)) {
+                const scope = $scope.$new();
+
+                if (_.isNil(paragraph.queryArgs.query)) {
+                    scope.title = 'SCAN query';
+                    scope.content = [`SCAN query for cache: <b>${$scope.maskCacheName(paragraph.queryArgs.cacheName)}</b>`];
+                }
+                else if (paragraph.queryArgs.query.startsWith(SCAN_CACHE_WITH_FILTER)) {
+                    scope.title = 'SCAN query';
+
+                    let filter = '';
+
+                    if (paragraph.queryArgs.query.startsWith(SCAN_CACHE_WITH_FILTER_CASE_SENSITIVE))
+                        filter = paragraph.queryArgs.query.substr(SCAN_CACHE_WITH_FILTER_CASE_SENSITIVE.length);
+                    else
+                        filter = paragraph.queryArgs.query.substr(SCAN_CACHE_WITH_FILTER.length);
+
+                    scope.content = [`SCAN query for cache: <b>${$scope.maskCacheName(paragraph.queryArgs.cacheName)}</b> with filter: <b>${filter}</b>`];
+                }
+                else if (paragraph.queryArgs.query .startsWith('EXPLAIN ')) {
+                    scope.title = 'Explain query';
+                    scope.content = [paragraph.queryArgs.query];
+                }
+                else {
+                    scope.title = 'SQL query';
+                    scope.content = [paragraph.queryArgs.query];
+                }
+
+                // Show a basic modal from a controller
+                $modal({scope, template: '/templates/message.html', placement: 'center', show: true});
+            }
+        };
+    }
+];

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/frontend/app/modules/sql/sql.module.js
----------------------------------------------------------------------
diff --git a/modules/web-console/frontend/app/modules/sql/sql.module.js b/modules/web-console/frontend/app/modules/sql/sql.module.js
new file mode 100644
index 0000000..d615d28
--- /dev/null
+++ b/modules/web-console/frontend/app/modules/sql/sql.module.js
@@ -0,0 +1,60 @@
+/*
+ * 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 NotebookData from './Notebook.data';
+import Notebook from './Notebook.service';
+import ScanFilterInput from './scan-filter-input.service';
+import notebook from './notebook.controller';
+import sql from './sql.controller';
+
+angular.module('ignite-console.sql', [
+    'ui.router'
+])
+    .config(['$stateProvider', 'AclRouteProvider',
+        ($stateProvider, AclRoute) => {
+            // set up the states
+            $stateProvider
+                .state('base.sql', {
+                    url: '/sql',
+                    abstract: true,
+                    template: '<ui-view></ui-view>'
+                })
+                .state('base.sql.notebook', {
+                    url: '/notebook/{noteId}',
+                    templateUrl: '/sql/sql.html',
+                    onEnter: AclRoute.checkAccess('query'),
+                    metaTags: {
+                        title: 'Query notebook'
+                    }
+                })
+                .state('base.sql.demo', {
+                    url: '/demo',
+                    templateUrl: '/sql/sql.html',
+                    onEnter: AclRoute.checkAccess('query'),
+                    metaTags: {
+                        title: 'SQL demo'
+                    }
+                });
+        }]
+    )
+    .service('IgniteNotebookData', NotebookData)
+    .service('IgniteNotebook', Notebook)
+    .service('IgniteScanFilterInput', ScanFilterInput)
+    .controller('notebookController', notebook)
+    .controller('sqlController', sql);

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/frontend/app/modules/states/admin.state.js
----------------------------------------------------------------------
diff --git a/modules/web-console/frontend/app/modules/states/admin.state.js b/modules/web-console/frontend/app/modules/states/admin.state.js
new file mode 100644
index 0000000..c3151e1
--- /dev/null
+++ b/modules/web-console/frontend/app/modules/states/admin.state.js
@@ -0,0 +1,35 @@
+/*
+ * 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';
+
+angular
+.module('ignite-console.states.admin', [
+    'ui.router'
+])
+.config(['$stateProvider', 'AclRouteProvider', function($stateProvider, AclRoute) {
+    // set up the states
+    $stateProvider
+    .state('settings.admin', {
+        url: '/admin',
+        templateUrl: '/settings/admin.html',
+        onEnter: AclRoute.checkAccess('admin_page'),
+        metaTags: {
+            title: 'List of registered users'
+        }
+    });
+}]);

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/frontend/app/modules/states/configuration.state.js
----------------------------------------------------------------------
diff --git a/modules/web-console/frontend/app/modules/states/configuration.state.js b/modules/web-console/frontend/app/modules/states/configuration.state.js
new file mode 100644
index 0000000..7fd7541
--- /dev/null
+++ b/modules/web-console/frontend/app/modules/states/configuration.state.js
@@ -0,0 +1,97 @@
+/*
+ * 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';
+
+// Common directives.
+import previewPanel from './configuration/preview-panel.directive.js';
+
+// Summary screen.
+import ConfigurationSummaryCtrl from './configuration/summary/summary.controller';
+import ConfigurationResource from './configuration/Configuration.resource';
+import summaryTabs from './configuration/summary/summary-tabs.directive';
+
+angular.module('ignite-console.states.configuration', ['ui.router'])
+    .directive(...previewPanel)
+    // Summary screen
+    .directive(...summaryTabs)
+    // Services.
+    .service('igniteConfigurationResource', ConfigurationResource)
+    // Configure state provider.
+    .config(['$stateProvider', 'AclRouteProvider', ($stateProvider, AclRoute) => {
+        // Setup the states.
+        $stateProvider
+            .state('base.configuration', {
+                url: '/configuration',
+                templateUrl: '/configuration/sidebar.html',
+                abstract: true
+            })
+            .state('base.configuration.clusters', {
+                url: '/clusters',
+                templateUrl: '/configuration/clusters.html',
+                onEnter: AclRoute.checkAccess('configuration'),
+                params: {
+                    linkId: null
+                },
+                metaTags: {
+                    title: 'Configure Clusters'
+                }
+            })
+            .state('base.configuration.caches', {
+                url: '/caches',
+                templateUrl: '/configuration/caches.html',
+                onEnter: AclRoute.checkAccess('configuration'),
+                params: {
+                    linkId: null
+                },
+                metaTags: {
+                    title: 'Configure Caches'
+                }
+            })
+            .state('base.configuration.domains', {
+                url: '/domains',
+                templateUrl: '/configuration/domains.html',
+                onEnter: AclRoute.checkAccess('configuration'),
+                params: {
+                    linkId: null
+                },
+                metaTags: {
+                    title: 'Configure Domain Model'
+                }
+            })
+            .state('base.configuration.igfs', {
+                url: '/igfs',
+                templateUrl: '/configuration/igfs.html',
+                onEnter: AclRoute.checkAccess('configuration'),
+                params: {
+                    linkId: null
+                },
+                metaTags: {
+                    title: 'Configure IGFS'
+                }
+            })
+            .state('base.configuration.summary', {
+                url: '/summary',
+                templateUrl: '/configuration/summary.html',
+                onEnter: AclRoute.checkAccess('configuration'),
+                controller: ConfigurationSummaryCtrl,
+                controllerAs: 'ctrl',
+                metaTags: {
+                    title: 'Configurations Summary'
+                }
+            });
+    }]);

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/frontend/app/modules/states/configuration/Configuration.resource.js
----------------------------------------------------------------------
diff --git a/modules/web-console/frontend/app/modules/states/configuration/Configuration.resource.js b/modules/web-console/frontend/app/modules/states/configuration/Configuration.resource.js
new file mode 100644
index 0000000..0582d5c
--- /dev/null
+++ b/modules/web-console/frontend/app/modules/states/configuration/Configuration.resource.js
@@ -0,0 +1,42 @@
+/*
+ * 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 ['$http', ($http) => {
+    return {
+        read() {
+            return $http.get('/api/v1/configuration/list')
+                .then(({data}) => data)
+                .catch(({data}) => Promise.reject(data));
+        },
+        populate({spaces, clusters, caches, igfss, domains}) {
+            _.forEach(clusters, (cluster) => {
+                cluster.caches = _.filter(caches, ({_id}) => _.includes(cluster.caches, _id));
+
+                _.forEach(cluster.caches, (cache) => {
+                    cache.domains = _.filter(domains, ({_id}) => _.includes(cache.domains, _id));
+
+                    if (_.get(cache, 'nodeFilter.kind') === 'IGFS')
+                        cache.nodeFilter.IGFS.instance = _.find(igfss, {_id: cache.nodeFilter.IGFS.igfs});
+                });
+
+                cluster.igfss = _.filter(igfss, ({_id}) => _.includes(cluster.igfss, _id));
+            });
+
+            return Promise.resolve({spaces, clusters, caches, igfss, domains});
+        }
+    };
+}];

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/frontend/app/modules/states/configuration/caches/concurrency.jade
----------------------------------------------------------------------
diff --git a/modules/web-console/frontend/app/modules/states/configuration/caches/concurrency.jade b/modules/web-console/frontend/app/modules/states/configuration/caches/concurrency.jade
new file mode 100644
index 0000000..37bd88d
--- /dev/null
+++ b/modules/web-console/frontend/app/modules/states/configuration/caches/concurrency.jade
@@ -0,0 +1,65 @@
+//-
+    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.jade
+
+-var form = 'concurrency'
+-var model = 'backupItem'
+
+.panel.panel-default(ng-form=form novalidate)
+    .panel-heading(bs-collapse-toggle='' ng-click='ui.loadPanel("#{form}")')
+        ignite-form-panel-chevron
+        label Concurrency control
+        ignite-form-field-tooltip.tipLabel
+            | Cache concurrent asynchronous operations settings
+        ignite-form-revert
+    .panel-collapse(role='tabpanel' bs-collapse-target id=form)
+        .panel-body(ng-if='ui.isPanelLoaded("#{form}")')
+            .col-sm-6
+                .settings-row
+                    +number('Max async operations:', model + '.maxConcurrentAsyncOperations', '"maxConcurrentAsyncOperations"', 'true', '500', '0',
+                        'Maximum number of allowed concurrent asynchronous operations<br/>\
+                        If <b>0</b> then number of concurrent asynchronous operations is unlimited')
+                .settings-row
+                    +number('Default lock timeout:', model + '.defaultLockTimeout', '"defaultLockTimeout"', 'true', '0', '0',
+                        'Default lock acquisition timeout in milliseconds<br/>\
+                        If <b>0</b> then lock acquisition will never timeout')
+                .settings-row(ng-hide='#{model}.atomicityMode === "TRANSACTIONAL"')
+                    +dropdown('Entry versioning:', model + '.atomicWriteOrderMode', '"atomicWriteOrderMode"', 'true', 'Choose versioning',
+                        '[\
+                            {value: "CLOCK", label: "CLOCK"},\
+                            {value: "PRIMARY", label: "PRIMARY"}\
+                        ]',
+                        'Write ordering mode determines which node assigns the write version, sender or the primary node\
+                        <ul>\
+                            <li>CLOCK - in this mode write versions are assigned on a sender node which generally leads to better performance</li>\
+                            <li>PRIMARY - in this mode version is assigned only on primary node. This means that sender will only send write request to primary node, which in turn will assign write version and forward it to backups</li>\
+                        </ul>')
+                .settings-row
+                    +dropdown('Write synchronization mode:', model + '.writeSynchronizationMode', '"writeSynchronizationMode"', 'true', 'PRIMARY_SYNC',
+                        '[\
+                            {value: "FULL_SYNC", label: "FULL_SYNC"},\
+                            {value: "FULL_ASYNC", label: "FULL_ASYNC"},\
+                            {value: "PRIMARY_SYNC", label: "PRIMARY_SYNC"}\
+                        ]',
+                        'Write synchronization mode\
+                        <ul>\
+                            <li>FULL_SYNC - Ignite will wait for write or commit replies from all nodes</li>\
+                            <li>FULL_ASYNC - Ignite will not wait for write or commit responses from participating nodes</li>\
+                            <li>PRIMARY_SYNC - Makes sense for PARTITIONED mode. Ignite will wait for write or commit to complete on primary node</li>\
+                        </ul>')
+            .col-sm-6
+                +preview-xml-java(model, 'cacheConcurrency')

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/frontend/app/modules/states/configuration/caches/general.jade
----------------------------------------------------------------------
diff --git a/modules/web-console/frontend/app/modules/states/configuration/caches/general.jade b/modules/web-console/frontend/app/modules/states/configuration/caches/general.jade
new file mode 100644
index 0000000..e3147b1
--- /dev/null
+++ b/modules/web-console/frontend/app/modules/states/configuration/caches/general.jade
@@ -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.
+
+include ../../../../../app/helpers/jade/mixins.jade
+
+-var form = 'general'
+-var model = 'backupItem'
+
+.panel.panel-default(ng-form=form novalidate)
+    .panel-heading(bs-collapse-toggle)
+        ignite-form-panel-chevron
+        label General
+        ignite-form-revert
+    .panel-collapse(role='tabpanel' bs-collapse-target id='general')
+        .panel-body
+            .col-sm-6
+                .settings-row
+                    +text('Name:', model + '.name', '"cacheName"', 'true', 'Input name', 'Cache name')
+                .settings-row
+                    +clusters(model, 'Associate clusters with the current cache')
+                .settings-row
+                    +dropdown-multiple('<span>Domain models:</span><a ui-sref="base.configuration.domains({linkId: linkId()})"> (add)</a>',
+                        model + '.domains', '"domains"', true, 'Choose domain models', 'No valid domain models configured', 'domains',
+                        'Select domain models to describe types in cache')
+                .settings-row
+                    +cacheMode('Mode:', model + '.cacheMode', '"cacheMode"', 'PARTITIONED')
+                .settings-row
+                    +dropdown('Atomicity:', model + '.atomicityMode', '"atomicityMode"', 'true', 'ATOMIC',
+                        '[\
+                            {value: "ATOMIC", label: "ATOMIC"},\
+                            {value: "TRANSACTIONAL", label: "TRANSACTIONAL"}\
+                        ]',
+                        'Atomicity:\
+                        <ul>\
+                            <li>ATOMIC - in this mode distributed transactions and distributed locking are not supported</li>\
+                            <li>TRANSACTIONAL - in this mode specified fully ACID-compliant transactional cache behavior</li>\
+                        </ul>')
+                .settings-row(data-ng-show='#{model}.cacheMode === "PARTITIONED"')
+                    +number('Backups:', model + '.backups', '"backups"', 'true', '0', '0', 'Number of nodes used to back up single partition for partitioned cache')
+                .settings-row(data-ng-show='#{model}.cacheMode === "PARTITIONED" && #{model}.backups')
+                    +checkbox('Read from backup', model + '.readFromBackup', '"readFromBackup"',
+                        'Flag indicating whether data can be read from backup<br/>\
+                        If not set then always get data from primary node (never from backup)')
+                .settings-row
+                    +checkbox('Copy on read', model + '.copyOnRead', '"copyOnRead"',
+                        'Flag indicating whether copy of the value stored in cache should be created for cache operation implying return value<br/>\
+                        Also if this flag is set copies are created for values passed to CacheInterceptor and to CacheEntryProcessor')
+                .settings-row(ng-show='#{model}.cacheMode === "PARTITIONED" && #{model}.atomicityMode === "TRANSACTIONAL"')
+                    +checkbox('Invalidate near cache', model + '.invalidate', '"invalidate"',
+                        'Invalidation flag for near cache entries in transaction<br/>\
+                        If set then values will be invalidated (nullified) upon commit in near cache')
+            .col-sm-6
+                +preview-xml-java(model, 'cacheGeneral')

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/frontend/app/modules/states/configuration/caches/memory.jade
----------------------------------------------------------------------
diff --git a/modules/web-console/frontend/app/modules/states/configuration/caches/memory.jade b/modules/web-console/frontend/app/modules/states/configuration/caches/memory.jade
new file mode 100644
index 0000000..debbe0d
--- /dev/null
+++ b/modules/web-console/frontend/app/modules/states/configuration/caches/memory.jade
@@ -0,0 +1,102 @@
+//-
+    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.jade
+
+-var form = 'memory'
+-var model = 'backupItem'
+
+.panel.panel-default(ng-form=form novalidate)
+    .panel-heading(bs-collapse-toggle='' ng-click='ui.loadPanel("#{form}")')
+        ignite-form-panel-chevron
+        label Memory
+        ignite-form-field-tooltip.tipLabel
+            | Cache memory settings
+        ignite-form-revert
+    .panel-collapse(role='tabpanel' bs-collapse-target id=form)
+        .panel-body(ng-if='ui.isPanelLoaded("#{form}")')
+            .col-sm-6
+                .settings-row
+                    +dropdown('Mode:', model + '.memoryMode', '"memoryMode"', 'true', 'ONHEAP_TIERED',
+                        '[\
+                            {value: "ONHEAP_TIERED", label: "ONHEAP_TIERED"},\
+                            {value: "OFFHEAP_TIERED", label: "OFFHEAP_TIERED"},\
+                            {value: "OFFHEAP_VALUES", label: "OFFHEAP_VALUES"}\
+                        ]',
+                        'Memory modes control whether value is stored in on-heap memory, off-heap memory, or swap space\
+                        <ul>\
+                            <li>\
+                                ONHEAP_TIERED - entries are cached on heap memory first<br/>\
+                                <ul>\
+                                    <li>\
+                                        If offheap memory is enabled and eviction policy evicts an entry from heap memory, entry will be moved to offheap memory<br/>\
+                                        If offheap memory is disabled, then entry is simply discarded\
+                                    </li>\
+                                    <li>\
+                                        If swap space is enabled and offheap memory fills up, then entry will be evicted into swap space<br/>\
+                                        If swap space is disabled, then entry will be discarded. If swap is enabled and offheap memory is disabled, then entry will be evicted directly from heap memory into swap\
+                                    </li>\
+                                </ul>\
+                            </li>\
+                            <li>\
+                                OFFHEAP_TIERED - works the same as ONHEAP_TIERED, except that entries never end up in heap memory and get stored in offheap memory right away<br/>\
+                                Entries get cached in offheap memory first and then get evicted to swap, if one is configured\
+                            </li>\
+                            <li>\
+                                OFFHEAP_VALUES - entry keys will be stored on heap memory, and values will be stored in offheap memory<br/>\
+                                Note that in this mode entries can be evicted only to swap\
+                            </li>\
+                        </ul>')
+                .settings-row(data-ng-show=model + '.memoryMode !== "OFFHEAP_VALUES"')
+                    +dropdown-required('Off-heap memory:', model + '.offHeapMode', '"offHeapMode"', 'true',
+                        model + '.memoryMode === "OFFHEAP_TIERED"',
+                        'Disabled',
+                        '[\
+                            {value: -1, label: "Disabled"},\
+                            {value: 1, label: "Limited"},\
+                            {value: 0, label: "Unlimited"}\
+                        ]',
+                        'Off-heap storage mode\
+                        <ul>\
+                            <li>Disabled - Off-heap storage is disabled</li>\
+                            <li>Limited - Off-heap storage has limited size</li>\
+                            <li>Unlimited - Off-heap storage grow infinitely (it is up to user to properly add and remove entries from cache to ensure that off-heap storage does not grow infinitely)</li>\
+                        </ul>')
+                .settings-row(data-ng-if=model + '.offHeapMode === 1 && ' + model + '.memoryMode !== "OFFHEAP_VALUES"')
+                    +number-required('Off-heap memory max size:', model + '.offHeapMaxMemory', '"offHeapMaxMemory"', 'true',
+                        model + '.offHeapMode === 1', '', 1,
+                        'Sets maximum amount of memory available to off-heap storage in bytes')
+                .settings-row
+                    -var onHeapTired = model + '.memoryMode === "ONHEAP_TIERED"'
+                    -var swapEnabled = model + '.swapEnabled'
+                    -var offHeapMaxMemory = model + '.offHeapMaxMemory'
+
+                    +evictionPolicy(model + '.evictionPolicy', '"evictionPolicy"', 'true',
+                        onHeapTired  + ' && (' + swapEnabled + '|| _.isNumber(' + offHeapMaxMemory + ') &&' + offHeapMaxMemory + ' >= 0)',
+                        'Optional cache eviction policy<br/>\
+                        Must be set for entries to be evicted from on-heap to off-heap or swap\
+                        <ul>\
+                            <li>Least Recently Used(LRU) - Eviction policy based on LRU algorithm and supports batch eviction</li>\
+                            <li>First In First Out (FIFO) - Eviction policy based on FIFO algorithm and supports batch eviction</li>\
+                            <li>SORTED - Eviction policy which will select the minimum cache entry for eviction</li>\
+                        </ul>')
+                .settings-row
+                    +number('Start size:', model + '.startSize', '"startSize"', 'true', '1500000', '0',
+                        'Initial cache size which will be used to pre-create internal hash table after start')
+                .settings-row
+                    +checkbox('Swap enabled', model + '.swapEnabled', '"swapEnabled"', 'Flag indicating whether swap storage is enabled or not for this cache')
+            .col-sm-6
+                +preview-xml-java(model, 'cacheMemory')


[51/52] ignite git commit: Web Console beta-3. Fixed import from database.

Posted by ak...@apache.org.
Web Console beta-3. Fixed import from database.


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

Branch: refs/heads/master
Commit: 2a117fec92d3455e53933cd3992ac73d2b2c0d3a
Parents: 769e0be
Author: Andrey Novikov <an...@apache.org>
Authored: Thu Sep 8 16:53:11 2016 +0700
Committer: Andrey Novikov <an...@apache.org>
Committed: Thu Sep 8 16:53:11 2016 +0700

----------------------------------------------------------------------
 .../web-console/frontend/controllers/domains-controller.js   | 8 +++++---
 1 file changed, 5 insertions(+), 3 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/ignite/blob/2a117fec/modules/web-console/frontend/controllers/domains-controller.js
----------------------------------------------------------------------
diff --git a/modules/web-console/frontend/controllers/domains-controller.js b/modules/web-console/frontend/controllers/domains-controller.js
index e520494..6cb3540 100644
--- a/modules/web-console/frontend/controllers/domains-controller.js
+++ b/modules/web-console/frontend/controllers/domains-controller.js
@@ -385,8 +385,10 @@ export default ['domainsController', [
         $scope.showImportDomainModal = function() {
             LegacyTable.tableReset();
 
-            FormUtils.confirmUnsavedChanges($scope.ui.inputForm.$dirty, function() {
-                if ($scope.ui.inputForm.$dirty)
+            const dirty = $scope.ui.inputForm && $scope.ui.inputForm.$dirty;
+
+            FormUtils.confirmUnsavedChanges(dirty, function() {
+                if (dirty)
                     $scope.backupItem = $scope.selectedItem ? angular.copy($scope.selectedItem) : prepareNewItem();
 
                 const demo = $root.IgniteDemoMode;
@@ -441,7 +443,7 @@ export default ['domainsController', [
 
                                     $scope.ui.selectedJdbcDriverJar = $scope.jdbcDriverJars[0].value;
 
-                                    FormUtils.confirmUnsavedChanges($scope.ui.inputForm.$dirty, () => {
+                                    FormUtils.confirmUnsavedChanges(dirty, () => {
                                         $scope.importDomain.action = 'connect';
                                         $scope.importDomain.tables = [];
 


[02/52] ignite git commit: Web Console beta-3.

Posted by ak...@apache.org.
http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/src/main/js/views/templates/getting-started.jade
----------------------------------------------------------------------
diff --git a/modules/web-console/src/main/js/views/templates/getting-started.jade b/modules/web-console/src/main/js/views/templates/getting-started.jade
deleted file mode 100644
index 98bc265..0000000
--- a/modules/web-console/src/main/js/views/templates/getting-started.jade
+++ /dev/null
@@ -1,32 +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.
-
-.modal.center(role='dialog')
-    .modal-dialog
-        .modal-content
-            #errors-container.modal-header.header
-                button.close(ng-click='close()' aria-hidden='true') &times;
-                h4.modal-title {{title}}
-            .getting-started
-                .col-xs-12(ng-bind-html='message')
-            .modal-footer
-                .checkbox
-                    label
-                        input(type='checkbox' ng-model='ui.showGettingStarted')
-                        | Show getting started on next login
-                a.btn.btn-primary(ng-disabled='isFirst()' ng-click='!isFirst() && prev()') Prev
-                a.btn.btn-primary(ng-disabled='isLast()' ng-click='!isLast() && next()') Next
-                a.btn.btn-primary(ng-click='close()') Close

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/src/main/js/views/templates/message.jade
----------------------------------------------------------------------
diff --git a/modules/web-console/src/main/js/views/templates/message.jade b/modules/web-console/src/main/js/views/templates/message.jade
deleted file mode 100644
index 6dcf445..0000000
--- a/modules/web-console/src/main/js/views/templates/message.jade
+++ /dev/null
@@ -1,26 +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.
-
-.modal(tabindex='-1' role='dialog')
-    .modal-dialog
-        .modal-content
-            .modal-header
-                button.close(ng-click='$hide()' aria-hidden='true') &times;
-                h4.modal-title {{title}}
-            .modal-body(ng-show='content')
-                p(ng-bind-html='content.join("<br/>")' style='text-align: left;')
-            .modal-footer
-                button.btn.btn-primary(id='confirm-btn-confirm' ng-click='$hide()') Ok

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/src/main/js/views/templates/pagination.jade
----------------------------------------------------------------------
diff --git a/modules/web-console/src/main/js/views/templates/pagination.jade b/modules/web-console/src/main/js/views/templates/pagination.jade
deleted file mode 100644
index 08ced60..0000000
--- a/modules/web-console/src/main/js/views/templates/pagination.jade
+++ /dev/null
@@ -1,32 +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.
-
-nav(ng-if='numPages && pages.length >= 2')
-    ul.pagination
-        li(ng-if='currentPage > 1')
-            a(href='javascript:void(0);' ng-click='selectPage(1)' bs-tooltip='' data-title='First page' data-placement='bottom')
-                i.fa.fa-angle-double-left
-        li(ng-if='currentPage > 1')
-            a(href='javascript:void(0);' ng-click='selectPage(currentPage-1)' bs-tooltip='' data-title='Previous page' data-placement='bottom')
-                i.fa.fa-angle-left
-        li(ng-repeat='page in pages' ng-class='{active: page==currentPage}')
-            a(href='javascript:void(0);' ng-click='selectPage(page)') {{page}}
-        li(ng-if='currentPage < numPages')
-            a(href='javascript:void(0);' ng-click='selectPage(currentPage+1)' bs-tooltip='' data-title='Next page' data-placement='bottom')
-                i.fa.fa-angle-right
-        li(ng-if='currentPage < numPages')
-            a(href='javascript:void(0);' ng-click='selectPage(numPages)' bs-tooltip='' data-title='Last page' data-placement='bottom')
-                i.fa.fa-angle-double-right
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/src/main/js/views/templates/select.jade
----------------------------------------------------------------------
diff --git a/modules/web-console/src/main/js/views/templates/select.jade b/modules/web-console/src/main/js/views/templates/select.jade
deleted file mode 100644
index 3feee61..0000000
--- a/modules/web-console/src/main/js/views/templates/select.jade
+++ /dev/null
@@ -1,26 +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.
-
-ul.select.dropdown-menu(tabindex='-1' ng-show='$isVisible()' role='select')
-    li(ng-if='$showAllNoneButtons || ($isMultiple && $matches.length > 2)')
-        a(id='li-dropdown-select-all' ng-click='$selectAll()') {{$allText}} ({{$matches.length}})
-        a(id='li-dropdown-select-none' ng-click='$selectNone()') {{$noneText}}
-        hr(style='margin: 5px 0')
-    li(role='presentation' ng-repeat='match in $matches')
-        hr(ng-if='match.value == undefined' style='margin: 5px 0')
-        a(id='li-dropdown-item-{{$index}}'  role='menuitem' tabindex='-1' ng-class='{active: $isActive($index)}' ng-click='$select($index, $event)' bs-tooltip='widthIsSufficient && !widthIsSufficient("li-dropdown-item-{{$index}}", $index, match.label) ? match.label : ""' data-placement='bottom')
-            i(class='{{$iconCheckmark}}' ng-if='$isActive($index)' ng-class='{active: $isActive($index)}')
-            span(ng-bind='match.label')

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/src/main/js/views/templates/validation-error.jade
----------------------------------------------------------------------
diff --git a/modules/web-console/src/main/js/views/templates/validation-error.jade b/modules/web-console/src/main/js/views/templates/validation-error.jade
deleted file mode 100644
index 13deb9b..0000000
--- a/modules/web-console/src/main/js/views/templates/validation-error.jade
+++ /dev/null
@@ -1,25 +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.
-
-.popover.validation-error
-    .arrow
-    .popover-content
-        table
-            tr
-                td
-                    label {{content}}&nbsp&nbsp
-                td
-                    button.close(id='popover-btn-close' ng-click='$hide()') &times;

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/src/test/js/routes/agent.js
----------------------------------------------------------------------
diff --git a/modules/web-console/src/test/js/routes/agent.js b/modules/web-console/src/test/js/routes/agent.js
deleted file mode 100644
index 1c4aff5..0000000
--- a/modules/web-console/src/test/js/routes/agent.js
+++ /dev/null
@@ -1,94 +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 request = require('supertest'),
-    should = require('should'),
-    app = require('../../app'),
-    fs = require('fs'),
-    https = require('https'),
-    config = require('../../helpers/configuration-loader.js'),
-    agentManager = require('../../agents/agent-manager');
-
-/**
- * Create HTTP server.
- */
-/**
- * Start agent server.
- */
-var agentServer = https.createServer({
-    key: fs.readFileSync(config.get('monitor:server:key')),
-    cert: fs.readFileSync(config.get('monitor:server:cert')),
-    passphrase: config.get('monitor:server:keyPassphrase')
-});
-
-agentServer.listen(config.get('monitor:server:port'));
-
-agentManager.createManager(agentServer);
-
-describe('request from agent', function() {
-    var agent = request.agent(app);
-
-    before(function (done) {
-        this.timeout(10000);
-
-        agent
-            .post('/login')
-            .send({email: 'test@test.com', password: 'test'})
-            .expect(302)
-            .end(function (err) {
-                if (error)
-                    throw error;
-
-                setTimeout(done, 5000);
-            });
-    });
-
-    it('should return topology snapshot', function(done){
-        agent
-            .post('/agent/topology')
-            .send({})
-            .end(function(err, nodes) {
-                if (error) {
-                    console.log(error.response.text);
-
-                    throw error;
-                }
-
-                console.log(nodes);
-
-                done();
-            });
-    });
-
-    //it('should query result', function(done){
-    //    agent
-    //        .post('/agent/query')
-    //        .send({
-    //            username: 'nva',
-    //            password: 'nva.141',
-    //            host: 'localhost',
-    //            port: '5432',
-    //            dbName: 'ggmonitor'
-    //        })
-    //        .end(function(err, res) {
-    //            if (err)
-    //                throw err;
-    //
-    //            done();
-    //        });
-    //});
-});

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/web-agent/.gitignore
----------------------------------------------------------------------
diff --git a/modules/web-console/web-agent/.gitignore b/modules/web-console/web-agent/.gitignore
new file mode 100644
index 0000000..57dd45e
--- /dev/null
+++ b/modules/web-console/web-agent/.gitignore
@@ -0,0 +1,2 @@
+logs/*.log.*
+jdbc-drivers/*.jar

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/web-agent/README.txt
----------------------------------------------------------------------
diff --git a/modules/web-console/web-agent/README.txt b/modules/web-console/web-agent/README.txt
new file mode 100644
index 0000000..c6e625b
--- /dev/null
+++ b/modules/web-console/web-agent/README.txt
@@ -0,0 +1,88 @@
+Ignite Web Agent
+======================================
+Ignite Web Agent is a java standalone application that allow to connect Ignite Grid to Ignite Web Console.
+Ignite Web Agent communicates with grid nodes via REST interface and connects to Ignite Web Console via web-socket.
+
+Two main functions of Ignite Web Agent:
+ 1. Proxy between Ignite Web Console and Ignite Grid to execute SQL statements and collect metrics for monitoring.
+   You may need to specify URI for connect to Ignite REST server via "-n" option.
+
+ 2. Proxy between Ignite Web Console and user RDBMS to collect database metadata for later CacheTypeMetadata configuration.
+   You may need to copy JDBC driver into "./jdbc-drivers" subfolder or specify path via "-d" option.
+
+Usage example:
+  ignite-web-agent.sh
+
+Configuration file:
+  Should be a file with simple line-oriented format as described here: http://docs.oracle.com/javase/7/docs/api/java/util/Properties.html#load(java.io.Reader)
+
+  Available entries names:
+    tokens
+    server-uri
+    node-uri
+    driver-folder
+
+  Example configuration file:
+    tokens=1a2b3c4d5f,2j1s134d12
+    serverURI=https://console.example.com:3001
+
+Security tokens:
+  1) By default security token of current user will be included into "default.properties" inside downloaded "ignite-web-agent-x.x.x.zip".
+  2) One can get/reset token in Web Console profile (https://<your_console_address>/settings/profile).
+  3) One may specify several comma separated tokens using configuration file or command line arguments of web agent.
+
+Ignite Web agent requirements:
+  1) In order to communicate with web agent Ignite node should be started with REST server (move ignite-rest-http folder from lib/optional/ to lib/).
+  2) Configure web agent serverURI property by Ignite node REST server URI.
+
+Options:
+  -h, --help
+     Print this help message
+  -c, --config
+     Path to configuration file
+  -d, --driver-folder
+     Path to folder with JDBC drivers, default value: ./jdbc-drivers
+  -n, --node-uri
+     URI for connect to Ignite REST server, default value:
+     http://localhost:8080
+  -s, --server-uri
+     URI for connect to Ignite Web Console via web-socket protocol, default
+     value: http://localhost:3001
+  -t, --tokens
+     User's security tokens
+
+How to build:
+  To build from sources run following command in Ignite project root folder:
+  mvn clean package -pl :ignite-web-agent -am -P web-console -DskipTests=true
+
+Demo of Ignite Web Agent:
+ In order to simplify evaluation demo mode was implemented. To start demo, you need to click button "Start demo".
+ New tab will be open with prepared demo data.
+
+ 1) Demo for import domain model from database.
+   In this mode an in-memory H2 database will be started.
+   How to evaluate:
+     1.1) Go to Ignite Web Console "Domain model" screen.
+     1.2) Click "Import from database". You should see modal with demo description.
+     1.3) Click "Next" button. You should see list of available schemas.
+     1.4) Click "Next" button. You should see list of available tables.
+     1.5) Click "Next" button. You should see import options.
+     1.6) Select some of them and click "Save".
+
+   2) Demo for SQL.
+     How to evaluate:
+     In this mode internal Ignite node will be started. Cache created and populated with data.
+       2.1) Click "SQL" in Ignite Web Console top menu.
+       2.2) "Demo" notebook with preconfigured queries will be opened.
+       2.3) You can also execute any SQL queries for tables: "Country, Department, Employee, Parking, Car".
+
+ For example:
+   2.4) Enter SQL statement:
+           SELECT p.name, count(*) AS cnt
+           FROM "ParkingCache".Parking p
+           INNER JOIN "CarCache".Car c
+             ON (p.id) = (c.parkingId)
+           GROUP BY P.NAME
+   2.5) Click "Execute" button. You should get some data in table.
+   2.6) Click charts buttons to see auto generated charts.
+

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/web-agent/assembly/release-web-agent.xml
----------------------------------------------------------------------
diff --git a/modules/web-console/web-agent/assembly/release-web-agent.xml b/modules/web-console/web-agent/assembly/release-web-agent.xml
new file mode 100644
index 0000000..bb994c0
--- /dev/null
+++ b/modules/web-console/web-agent/assembly/release-web-agent.xml
@@ -0,0 +1,66 @@
+<?xml version="1.0" encoding="UTF-8"?>
+
+<!--
+  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.
+-->
+
+<assembly xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+          xmlns="http://maven.apache.org/plugins/maven-assembly-plugin/assembly/1.1.3"
+          xsi:schemaLocation="http://maven.apache.org/plugins/maven-assembly-plugin/assembly/1.1.3 http://maven.apache.org/xsd/assembly-1.1.3.xsd">
+    <id>release-ignite-web-agent</id>
+
+    <formats>
+        <format>zip</format>
+    </formats>
+
+    <fileSets>
+        <fileSet>
+            <directory>${basedir}</directory>
+            <outputDirectory>/</outputDirectory>
+            <includes>
+                <include>jdbc-drivers/README*</include>
+                <include>demo/README*</include>
+                <include>demo/*.sql</include>
+                <include>logs/README*</include>
+                <include>README*</include>
+                <include>LICENSE*</include>
+                <include>NOTICE*</include>
+            </includes>
+        </fileSet>
+        <fileSet>
+            <directory>${basedir}/bin</directory>
+            <outputDirectory>/</outputDirectory>
+            <includes>
+                <include>**/*.bat</include>
+            </includes>
+        </fileSet>
+        <fileSet>
+            <directory>${basedir}/bin</directory>
+            <outputDirectory>/</outputDirectory>
+            <fileMode>0755</fileMode>
+            <includes>
+                <include>**/*.sh</include>
+            </includes>
+        </fileSet>
+        <fileSet>
+            <directory>${project.build.directory}</directory>
+            <outputDirectory>/</outputDirectory>
+            <includes>
+                <include>ignite-web-agent-${project.version}.jar</include>
+            </includes>
+        </fileSet>
+    </fileSets>
+</assembly>

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/web-agent/bin/ignite-web-agent.bat
----------------------------------------------------------------------
diff --git a/modules/web-console/web-agent/bin/ignite-web-agent.bat b/modules/web-console/web-agent/bin/ignite-web-agent.bat
new file mode 100644
index 0000000..f16eb35
--- /dev/null
+++ b/modules/web-console/web-agent/bin/ignite-web-agent.bat
@@ -0,0 +1,70 @@
+::
+:: 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.
+::
+
+@echo off
+Setlocal EnableDelayedExpansion
+
+if "%OS%" == "Windows_NT"  setlocal
+
+:: Check JAVA_HOME.
+if defined JAVA_HOME  goto checkJdk
+    echo %0, ERROR:
+    echo JAVA_HOME environment variable is not found.
+    echo Please point JAVA_HOME variable to location of JDK 1.7 or JDK 1.8.
+    echo You can also download latest JDK at http://java.com/download.
+goto error_finish
+
+:checkJdk
+:: Check that JDK is where it should be.
+if exist "%JAVA_HOME%\bin\java.exe" goto checkJdkVersion
+    echo %0, ERROR:
+    echo JAVA is not found in JAVA_HOME=%JAVA_HOME%.
+    echo Please point JAVA_HOME variable to installation of JDK 1.7 or JDK 1.8.
+    echo You can also download latest JDK at http://java.com/download.
+goto error_finish
+
+:checkJdkVersion
+"%JAVA_HOME%\bin\java.exe" -version 2>&1 | findstr "1\.[78]\." > nul
+if %ERRORLEVEL% equ 0 goto run_java
+    echo %0, ERROR:
+    echo The version of JAVA installed in %JAVA_HOME% is incorrect.
+    echo Please point JAVA_HOME variable to installation of JDK 1.7 or JDK 1.8.
+    echo You can also download latest JDK at http://java.com/download.
+goto error_finish
+
+:run_java
+
+::
+:: JVM options. See http://java.sun.com/javase/technologies/hotspot/vmoptions.jsp for more details.
+::
+:: ADD YOUR/CHANGE ADDITIONAL OPTIONS HERE
+::
+if "%JVM_OPTS%" == "" set JVM_OPTS=-Xms1g -Xmx1g -server -XX:+AggressiveOpts -XX:MaxPermSize=256m
+
+"%JAVA_HOME%\bin\java.exe" %JVM_OPTS% -cp "*" org.apache.ignite.console.agent.AgentLauncher  %*
+
+set JAVA_ERRORLEVEL=%ERRORLEVEL%
+
+:: errorlevel 130 if aborted with Ctrl+c
+if %JAVA_ERRORLEVEL%==130 goto eof
+
+:error_finish
+
+if not "%NO_PAUSE%" == "1" pause
+
+goto :eof
+

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/web-agent/bin/ignite-web-agent.sh
----------------------------------------------------------------------
diff --git a/modules/web-console/web-agent/bin/ignite-web-agent.sh b/modules/web-console/web-agent/bin/ignite-web-agent.sh
new file mode 100644
index 0000000..3f2c2bc
--- /dev/null
+++ b/modules/web-console/web-agent/bin/ignite-web-agent.sh
@@ -0,0 +1,87 @@
+#!/bin/bash
+#
+# 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.
+#
+
+# Check JAVA_HOME.
+if [ "$JAVA_HOME" = "" ]; then
+    JAVA=`type -p java`
+    RETCODE=$?
+
+    if [ $RETCODE -ne 0 ]; then
+        echo $0", ERROR:"
+        echo "JAVA_HOME environment variable is not found."
+        echo "Please point JAVA_HOME variable to location of JDK 1.7 or JDK 1.8."
+        echo "You can also download latest JDK at http://java.com/download"
+
+        exit 1
+    fi
+
+    JAVA_HOME=
+else
+    JAVA=${JAVA_HOME}/bin/java
+fi
+
+#
+# Check JDK.
+#
+if [ ! -e "$JAVA" ]; then
+    echo $0", ERROR:"
+    echo "JAVA is not found in JAVA_HOME=$JAVA_HOME."
+    echo "Please point JAVA_HOME variable to installation of JDK 1.7 or JDK 1.8."
+    echo "You can also download latest JDK at http://java.com/download"
+
+    exit 1
+fi
+
+JAVA_VER=`"$JAVA" -version 2>&1 | egrep "1\.[78]\."`
+
+if [ "$JAVA_VER" == "" ]; then
+    echo $0", ERROR:"
+    echo "The version of JAVA installed in JAVA_HOME=$JAVA_HOME is incorrect."
+    echo "Please point JAVA_HOME variable to installation of JDK 1.7 or JDK 1.8."
+    echo "You can also download latest JDK at http://java.com/download"
+
+    exit 1
+fi
+
+SOURCE="${BASH_SOURCE[0]}"
+
+DIR="$( dirname "$SOURCE" )"
+
+while [ -h "$SOURCE" ]
+    do
+        SOURCE="$(readlink "$SOURCE")"
+
+        [[ $SOURCE != /* ]] && SOURCE="$DIR/$SOURCE"
+
+        DIR="$( cd -P "$( dirname "$SOURCE"  )" && pwd )"
+    done
+
+DIR="$( cd -P "$( dirname "$SOURCE" )" && pwd )"
+
+cd $DIR
+
+#
+# JVM options. See http://java.sun.com/javase/technologies/hotspot/vmoptions.jsp for more details.
+#
+# ADD YOUR/CHANGE ADDITIONAL OPTIONS HERE
+#
+if [ -z "$JVM_OPTS" ] ; then
+    JVM_OPTS="-Xms1g -Xmx1g -server -XX:+AggressiveOpts -XX:MaxPermSize=256m"
+fi
+
+"$JAVA" ${JVM_OPTS} -cp "*" org.apache.ignite.console.agent.AgentLauncher "$@"

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/web-agent/demo/README.txt
----------------------------------------------------------------------
diff --git a/modules/web-console/web-agent/demo/README.txt b/modules/web-console/web-agent/demo/README.txt
new file mode 100644
index 0000000..17e5074
--- /dev/null
+++ b/modules/web-console/web-agent/demo/README.txt
@@ -0,0 +1,4 @@
+Ignite Web Agent
+======================================
+
+This is folder for demo files.

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/web-agent/demo/db-init.sql
----------------------------------------------------------------------
diff --git a/modules/web-console/web-agent/demo/db-init.sql b/modules/web-console/web-agent/demo/db-init.sql
new file mode 100644
index 0000000..0688ea0
--- /dev/null
+++ b/modules/web-console/web-agent/demo/db-init.sql
@@ -0,0 +1,102 @@
+--
+--  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.
+--
+
+CREATE TABLE COUNTRY (
+    ID         INTEGER NOT NULL PRIMARY KEY,
+    NAME       VARCHAR(50),
+    POPULATION INTEGER NOT NULL
+);
+
+CREATE TABLE DEPARTMENT (
+    ID         INTEGER NOT NULL PRIMARY KEY,
+    COUNTRY_ID INTEGER NOT NULL,
+    NAME       VARCHAR(50) NOT NULL
+);
+
+CREATE TABLE EMPLOYEE (
+    ID            INTEGER NOT NULL PRIMARY KEY,
+    DEPARTMENT_ID INTEGER NOT NULL,
+    MANAGER_ID    INTEGER,
+    FIRST_NAME    VARCHAR(50) NOT NULL,
+    LAST_NAME     VARCHAR(50) NOT NULL,
+    EMAIL         VARCHAR(50) NOT NULL,
+    PHONE_NUMBER  VARCHAR(50),
+    HIRE_DATE     DATE        NOT NULL,
+    JOB           VARCHAR(50) NOT NULL,
+    SALARY        DOUBLE
+);
+
+CREATE INDEX EMP_SALARY ON EMPLOYEE (SALARY ASC);
+CREATE INDEX EMP_NAMES ON EMPLOYEE (FIRST_NAME ASC, LAST_NAME ASC);
+
+CREATE SCHEMA CARS;
+
+CREATE TABLE CARS.PARKING (
+    ID       INTEGER     NOT NULL PRIMARY KEY,
+    NAME     VARCHAR(50) NOT NULL,
+    CAPACITY INTEGER NOT NULL
+);
+
+CREATE TABLE CARS.CAR (
+    ID         INTEGER NOT NULL PRIMARY KEY,
+    PARKING_ID INTEGER NOT NULL,
+    NAME       VARCHAR(50) NOT NULL
+);
+
+INSERT INTO COUNTRY(ID, NAME, POPULATION) VALUES(0, 'Country #1', 10000000);
+INSERT INTO COUNTRY(ID, NAME, POPULATION) VALUES(1, 'Country #2', 20000000);
+INSERT INTO COUNTRY(ID, NAME, POPULATION) VALUES(2, 'Country #3', 30000000);
+
+INSERT INTO DEPARTMENT(ID, COUNTRY_ID, NAME) VALUES(0, 0, 'Department #1');
+INSERT INTO DEPARTMENT(ID, COUNTRY_ID, NAME) VALUES(1, 0, 'Department #2');
+INSERT INTO DEPARTMENT(ID, COUNTRY_ID, NAME) VALUES(2, 2, 'Department #3');
+INSERT INTO DEPARTMENT(ID, COUNTRY_ID, NAME) VALUES(3, 1, 'Department #4');
+INSERT INTO DEPARTMENT(ID, COUNTRY_ID, NAME) VALUES(4, 1, 'Department #5');
+INSERT INTO DEPARTMENT(ID, COUNTRY_ID, NAME) VALUES(5, 1, 'Department #6');
+
+INSERT INTO EMPLOYEE(ID, DEPARTMENT_ID, FIRST_NAME, LAST_NAME, EMAIL, PHONE_NUMBER, HIRE_DATE, JOB, SALARY) VALUES(0, 0, 'First name manager #1', 'Last name manager #1', 'Email manager #1', 'Phone number manager #1', '2014-01-01', 'Job manager #1', 1100.00);
+INSERT INTO EMPLOYEE(ID, DEPARTMENT_ID, FIRST_NAME, LAST_NAME, EMAIL, PHONE_NUMBER, HIRE_DATE, JOB, SALARY) VALUES(1, 1, 'First name manager #2', 'Last name manager #2', 'Email manager #2', 'Phone number manager #2', '2014-01-01', 'Job manager #2', 2100.00);
+INSERT INTO EMPLOYEE(ID, DEPARTMENT_ID, FIRST_NAME, LAST_NAME, EMAIL, PHONE_NUMBER, HIRE_DATE, JOB, SALARY) VALUES(2, 2, 'First name manager #3', 'Last name manager #3', 'Email manager #3', 'Phone number manager #3', '2014-01-01', 'Job manager #3', 3100.00);
+INSERT INTO EMPLOYEE(ID, DEPARTMENT_ID, FIRST_NAME, LAST_NAME, EMAIL, PHONE_NUMBER, HIRE_DATE, JOB, SALARY) VALUES(3, 3, 'First name manager #4', 'Last name manager #4', 'Email manager #4', 'Phone number manager #4', '2014-01-01', 'Job manager #4', 1500.00);
+INSERT INTO EMPLOYEE(ID, DEPARTMENT_ID, FIRST_NAME, LAST_NAME, EMAIL, PHONE_NUMBER, HIRE_DATE, JOB, SALARY) VALUES(4, 4, 'First name manager #5', 'Last name manager #5', 'Email manager #5', 'Phone number manager #5', '2014-01-01', 'Job manager #5', 1700.00);
+INSERT INTO EMPLOYEE(ID, DEPARTMENT_ID, FIRST_NAME, LAST_NAME, EMAIL, PHONE_NUMBER, HIRE_DATE, JOB, SALARY) VALUES(5, 5, 'First name manager #6', 'Last name manager #6', 'Email manager #6', 'Phone number manager #6', '2014-01-01', 'Job manager #6', 1300.00);
+
+INSERT INTO EMPLOYEE(ID, DEPARTMENT_ID, MANAGER_ID, FIRST_NAME, LAST_NAME, EMAIL, PHONE_NUMBER, HIRE_DATE, JOB, SALARY) VALUES(101, 0, 0, 'First name employee #1', 'Last name employee #1', 'Email employee #1', 'Phone number employee #1', '2014-01-01', 'Job employee #1', 600.00);
+INSERT INTO EMPLOYEE(ID, DEPARTMENT_ID, MANAGER_ID, FIRST_NAME, LAST_NAME, EMAIL, PHONE_NUMBER, HIRE_DATE, JOB, SALARY) VALUES(102, 0, 0, 'First name employee #2', 'Last name employee #2', 'Email employee #2', 'Phone number employee #2', '2014-01-01', 'Job employee #2', 1600.00);
+INSERT INTO EMPLOYEE(ID, DEPARTMENT_ID, MANAGER_ID, FIRST_NAME, LAST_NAME, EMAIL, PHONE_NUMBER, HIRE_DATE, JOB, SALARY) VALUES(103, 1, 1, 'First name employee #3', 'Last name employee #3', 'Email employee #3', 'Phone number employee #3', '2014-01-01', 'Job employee #3', 2600.00);
+INSERT INTO EMPLOYEE(ID, DEPARTMENT_ID, MANAGER_ID, FIRST_NAME, LAST_NAME, EMAIL, PHONE_NUMBER, HIRE_DATE, JOB, SALARY) VALUES(104, 2, 2, 'First name employee #4', 'Last name employee #4', 'Email employee #4', 'Phone number employee #4', '2014-01-01', 'Job employee #4', 1000.00);
+INSERT INTO EMPLOYEE(ID, DEPARTMENT_ID, MANAGER_ID, FIRST_NAME, LAST_NAME, EMAIL, PHONE_NUMBER, HIRE_DATE, JOB, SALARY) VALUES(105, 2, 2, 'First name employee #5', 'Last name employee #5', 'Email employee #5', 'Phone number employee #5', '2014-01-01', 'Job employee #5', 1200.00);
+INSERT INTO EMPLOYEE(ID, DEPARTMENT_ID, MANAGER_ID, FIRST_NAME, LAST_NAME, EMAIL, PHONE_NUMBER, HIRE_DATE, JOB, SALARY) VALUES(106, 2, 2, 'First name employee #6', 'Last name employee #6', 'Email employee #6', 'Phone number employee #6', '2014-01-01', 'Job employee #6', 800.00);
+INSERT INTO EMPLOYEE(ID, DEPARTMENT_ID, MANAGER_ID, FIRST_NAME, LAST_NAME, EMAIL, PHONE_NUMBER, HIRE_DATE, JOB, SALARY) VALUES(107, 3, 3, 'First name employee #7', 'Last name employee #7', 'Email employee #7', 'Phone number employee #7', '2014-01-01', 'Job employee #7', 1400.00);
+INSERT INTO EMPLOYEE(ID, DEPARTMENT_ID, MANAGER_ID, FIRST_NAME, LAST_NAME, EMAIL, PHONE_NUMBER, HIRE_DATE, JOB, SALARY) VALUES(108, 4, 4, 'First name employee #8', 'Last name employee #8', 'Email employee #8', 'Phone number employee #8', '2014-01-01', 'Job employee #8', 800.00);
+INSERT INTO EMPLOYEE(ID, DEPARTMENT_ID, MANAGER_ID, FIRST_NAME, LAST_NAME, EMAIL, PHONE_NUMBER, HIRE_DATE, JOB, SALARY) VALUES(109, 4, 4, 'First name employee #9', 'Last name employee #9', 'Email employee #9', 'Phone number employee #9', '2014-01-01', 'Job employee #9', 1490.00);
+INSERT INTO EMPLOYEE(ID, DEPARTMENT_ID, MANAGER_ID, FIRST_NAME, LAST_NAME, EMAIL, PHONE_NUMBER, HIRE_DATE, JOB, SALARY) VALUES(110, 4, 4, 'First name employee #10', 'Last name employee #12', 'Email employee #10', 'Phone number employee #10', '2014-01-01', 'Job employee #10', 1600.00);
+INSERT INTO EMPLOYEE(ID, DEPARTMENT_ID, MANAGER_ID, FIRST_NAME, LAST_NAME, EMAIL, PHONE_NUMBER, HIRE_DATE, JOB, SALARY) VALUES(111, 5, 5, 'First name employee #11', 'Last name employee #11', 'Email employee #11', 'Phone number employee #11', '2014-01-01', 'Job employee #11', 400.00);
+
+INSERT INTO CARS.PARKING(ID, NAME, CAPACITY) VALUES(0, 'Parking #1', 10);
+INSERT INTO CARS.PARKING(ID, NAME, CAPACITY) VALUES(1, 'Parking #2', 20);
+INSERT INTO CARS.PARKING(ID, NAME, CAPACITY) VALUES(2, 'Parking #3', 30);
+
+INSERT INTO CARS.CAR(ID, PARKING_ID, NAME) VALUES(0, 0, 'Car #1');
+INSERT INTO CARS.CAR(ID, PARKING_ID, NAME) VALUES(1, 0, 'Car #2');
+INSERT INTO CARS.CAR(ID, PARKING_ID, NAME) VALUES(2, 0, 'Car #3');
+INSERT INTO CARS.CAR(ID, PARKING_ID, NAME) VALUES(3, 1, 'Car #4');
+INSERT INTO CARS.CAR(ID, PARKING_ID, NAME) VALUES(4, 1, 'Car #5');
+INSERT INTO CARS.CAR(ID, PARKING_ID, NAME) VALUES(5, 2, 'Car #6');
+INSERT INTO CARS.CAR(ID, PARKING_ID, NAME) VALUES(6, 2, 'Car #7');
+INSERT INTO CARS.CAR(ID, PARKING_ID, NAME) VALUES(7, 2, 'Car #8');
+INSERT INTO CARS.CAR(ID, PARKING_ID, NAME) VALUES(8, 2, 'Car #9');

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/web-agent/jdbc-drivers/README.txt
----------------------------------------------------------------------
diff --git a/modules/web-console/web-agent/jdbc-drivers/README.txt b/modules/web-console/web-agent/jdbc-drivers/README.txt
new file mode 100644
index 0000000..cad43b7
--- /dev/null
+++ b/modules/web-console/web-agent/jdbc-drivers/README.txt
@@ -0,0 +1,10 @@
+Ignite Web Agent
+======================================
+
+If you are are planning to load cache type metadata from your existing databases
+you need to copy JDBC drivers in this folder.
+
+This is default folder for JDBC drivers.
+
+Also, you could specify custom folder using option: "-d CUSTOM_PATH_TO_FOLDER_WITH_JDBC_DRIVERS".
+

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/web-agent/logs/README.txt
----------------------------------------------------------------------
diff --git a/modules/web-console/web-agent/logs/README.txt b/modules/web-console/web-agent/logs/README.txt
new file mode 100644
index 0000000..3a220eb
--- /dev/null
+++ b/modules/web-console/web-agent/logs/README.txt
@@ -0,0 +1,5 @@
+Ignite Web Agent
+======================================
+
+This is folder for agent logs.
+

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/web-agent/pom.xml
----------------------------------------------------------------------
diff --git a/modules/web-console/web-agent/pom.xml b/modules/web-console/web-agent/pom.xml
new file mode 100644
index 0000000..530a272
--- /dev/null
+++ b/modules/web-console/web-agent/pom.xml
@@ -0,0 +1,199 @@
+<?xml version="1.0" encoding="UTF-8"?>
+
+<!--
+  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.
+-->
+
+<!--
+    POM file.
+-->
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+    <modelVersion>4.0.0</modelVersion>
+
+    <parent>
+        <groupId>org.apache.ignite</groupId>
+        <artifactId>ignite-parent</artifactId>
+        <version>1</version>
+        <relativePath>../../../parent</relativePath>
+    </parent>
+
+    <artifactId>ignite-web-agent</artifactId>
+    <packaging>jar</packaging>
+    <version>1.7.0-SNAPSHOT</version>
+    <url>http://ignite.apache.org</url>
+
+    <properties>
+        <maven.build.timestamp.format>yyMMddHHmmss</maven.build.timestamp.format>
+    </properties>
+
+    <dependencies>
+        <dependency>
+            <groupId>io.socket</groupId>
+            <artifactId>socket.io-client</artifactId>
+            <version>0.7.0</version>
+        </dependency>
+
+        <dependency>
+            <groupId>com.fasterxml.jackson.datatype</groupId>
+            <artifactId>jackson-datatype-json-org</artifactId>
+            <version>${jackson2.version}</version>
+        </dependency>
+
+        <dependency>
+            <groupId>com.beust</groupId>
+            <artifactId>jcommander</artifactId>
+            <version>1.48</version>
+        </dependency>
+
+        <dependency>
+            <groupId>org.apache.httpcomponents</groupId>
+            <artifactId>httpclient</artifactId>
+            <version>${httpclient.version}</version>
+        </dependency>
+
+        <dependency>
+            <groupId>org.apache.ignite</groupId>
+            <artifactId>ignite-schema-import-db</artifactId>
+            <version>${project.version}</version>
+            <exclusions>
+                <exclusion>
+                    <groupId>org.gridgain</groupId>
+                    <artifactId>ignite-shmem</artifactId>
+                </exclusion>
+            </exclusions>
+        </dependency>
+
+        <dependency>
+            <groupId>org.apache.ignite</groupId>
+            <artifactId>ignite-indexing</artifactId>
+            <version>${project.version}</version>
+        </dependency>
+
+        <dependency>
+            <groupId>org.apache.ignite</groupId>
+            <artifactId>ignite-rest-http</artifactId>
+            <version>${project.version}</version>
+        </dependency>
+
+        <dependency>
+            <groupId>org.apache.ignite</groupId>
+            <artifactId>ignite-spring</artifactId>
+            <version>${project.version}</version>
+            <exclusions>
+                <exclusion>
+                    <groupId>org.springframework</groupId>
+                    <artifactId>spring-aop</artifactId>
+                </exclusion>
+                <exclusion>
+                    <groupId>org.springframework</groupId>
+                    <artifactId>spring-tx</artifactId>
+                </exclusion>
+                <exclusion>
+                    <groupId>org.springframework</groupId>
+                    <artifactId>spring-jdbc</artifactId>
+                </exclusion>
+            </exclusions>
+        </dependency>
+
+        <dependency>
+            <groupId>org.apache.ignite</groupId>
+            <artifactId>ignite-log4j</artifactId>
+            <version>${project.version}</version>
+        </dependency>
+    </dependencies>
+
+    <build>
+        <finalName>ignite-web-agent-${project.version}</finalName>
+
+        <plugins>
+            <plugin>
+                <artifactId>maven-jar-plugin</artifactId>
+                <version>2.5</version>
+
+                <configuration>
+                    <archive>
+                        <manifest>
+                            <mainClass>org.apache.ignite.console.agent.AgentLauncher</mainClass>
+                        </manifest>
+                        <manifestEntries>
+                            <Build-Time>${maven.build.timestamp}</Build-Time>
+                        </manifestEntries>
+                    </archive>
+                </configuration>
+            </plugin>
+
+            <plugin>
+                <groupId>org.apache.maven.plugins</groupId>
+                <artifactId>maven-shade-plugin</artifactId>
+                <version>2.4</version>
+
+                <executions>
+                    <execution>
+                        <phase>package</phase>
+                        <goals>
+                            <goal>shade</goal>
+                        </goals>
+
+                        <configuration>
+                            <createDependencyReducedPom>false</createDependencyReducedPom>
+                            <filters>
+                                <filter>
+                                    <artifact>*:*</artifact>
+                                    <excludes>
+                                        <exclude>META-INF/maven/**</exclude>
+                                    </excludes>
+                                </filter>
+                            </filters>
+                        </configuration>
+                    </execution>
+                </executions>
+            </plugin>
+
+            <plugin>
+                <groupId>org.apache.maven.plugins</groupId>
+                <artifactId>maven-assembly-plugin</artifactId>
+                <version>2.4</version>
+                <inherited>false</inherited>
+
+                <executions>
+                    <execution>
+                        <id>release-web-agent</id>
+                        <phase>package</phase>
+                        <goals>
+                            <goal>single</goal>
+                        </goals>
+                        <configuration>
+                            <descriptors>
+                                <descriptor>assembly/release-web-agent.xml</descriptor>
+                            </descriptors>
+                            <finalName>ignite-web-agent-${project.version}</finalName>
+                            <outputDirectory>target</outputDirectory>
+                            <appendAssemblyId>false</appendAssemblyId>
+                        </configuration>
+                    </execution>
+                </executions>
+            </plugin>
+
+            <plugin>
+                <groupId>org.apache.maven.plugins</groupId>
+                <artifactId>maven-deploy-plugin</artifactId>
+                <configuration>
+                    <skip>true</skip>
+                </configuration>
+            </plugin>
+        </plugins>
+    </build>
+</project>

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/web-agent/src/main/java/org/apache/ignite/console/agent/AgentConfiguration.java
----------------------------------------------------------------------
diff --git a/modules/web-console/web-agent/src/main/java/org/apache/ignite/console/agent/AgentConfiguration.java b/modules/web-console/web-agent/src/main/java/org/apache/ignite/console/agent/AgentConfiguration.java
new file mode 100644
index 0000000..d4787cc
--- /dev/null
+++ b/modules/web-console/web-agent/src/main/java/org/apache/ignite/console/agent/AgentConfiguration.java
@@ -0,0 +1,268 @@
+/*
+ * 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.
+ */
+
+package org.apache.ignite.console.agent;
+
+import com.beust.jcommander.Parameter;
+import java.io.File;
+import java.io.IOException;
+import java.io.InputStreamReader;
+import java.io.Reader;
+import java.net.URL;
+import java.util.Arrays;
+import java.util.List;
+import java.util.Properties;
+
+/**
+ * Agent configuration.
+ */
+public class AgentConfiguration {
+    /** Default server port. */
+    public static final int DFLT_SERVER_PORT = 3001;
+
+    /** Default Ignite node HTTP port. */
+    public static final int DFLT_NODE_PORT = 8080;
+
+    /** Default path to agent property file. */
+    public static final String DFLT_CFG_PATH = "default.properties";
+
+    /** Default server URI. */
+    private static final String DFLT_SERVER_URI = "http://localhost:3001";
+
+    /** Default Ignite node HTTP URI. */
+    private static final String DFLT_NODE_URI = "http://localhost:8080";
+
+    /** */
+    @Parameter(names = {"-t", "--tokens"},
+        description = "User's tokens separated by comma used to connect to Ignite Console.")
+    private List<String> tokens;
+
+    /** */
+    @Parameter(names = {"-s", "--server-uri"},
+        description = "URI for connect to Ignite Console via web-socket protocol" +
+        "           " +
+        "      Default value: " + DFLT_SERVER_URI)
+    private String srvUri;
+
+    /** */
+    @Parameter(names = {"-n", "--node-uri"}, description = "URI for connect to Ignite node REST server" +
+        "                        " +
+        "      Default value: " + DFLT_NODE_URI)
+    private String nodeUri;
+
+    /** URI for connect to Ignite demo node REST server */
+    private String demoNodeUri;
+
+    /** */
+    @Parameter(names = {"-c", "--config"}, description = "Path to agent property file" +
+        "                                  " +
+        "      Default value: " + DFLT_CFG_PATH)
+    private String cfgPath;
+
+    /** */
+    @Parameter(names = {"-d", "--driver-folder"}, description = "Path to folder with JDBC drivers" +
+        "                             " +
+        "      Default value: ./jdbc-drivers")
+    private String driversFolder;
+
+    /** */
+    @Parameter(names = { "-h", "--help" }, help = true, description = "Print this help message")
+    private Boolean help;
+
+    /**
+     * @return Tokens.
+     */
+    public List<String> tokens() {
+        return tokens;
+    }
+
+    /**
+     * @param tokens Tokens.
+     */
+    public void tokens(List<String> tokens) {
+        this.tokens = tokens;
+    }
+
+    /**
+     * @return Server URI.
+     */
+    public String serverUri() {
+        return srvUri;
+    }
+
+    /**
+     * @param srvUri URI.
+     */
+    public void serverUri(String srvUri) {
+        this.srvUri = srvUri;
+    }
+
+    /**
+     * @return Node URI.
+     */
+    public String nodeUri() {
+        return nodeUri;
+    }
+
+    /**
+     * @param nodeUri Node URI.
+     */
+    public void nodeUri(String nodeUri) {
+        this.nodeUri = nodeUri;
+    }
+
+    /**
+     * @return Demo node URI.
+     */
+    public String demoNodeUri() {
+        return demoNodeUri;
+    }
+
+    /**
+     * @param demoNodeUri Demo node URI.
+     */
+    public void demoNodeUri(String demoNodeUri) {
+        this.demoNodeUri = demoNodeUri;
+    }
+
+    /**
+     * @return Configuration path.
+     */
+    public String configPath() {
+        return cfgPath == null ? DFLT_CFG_PATH : cfgPath;
+    }
+
+    /**
+     * @return Configured drivers folder.
+     */
+    public String driversFolder() {
+        return driversFolder;
+    }
+
+    /**
+     * @param driversFolder Driver folder.
+     */
+    public void driversFolder(String driversFolder) {
+        this.driversFolder = driversFolder;
+    }
+
+    /**
+     * @return {@code true} If agent options usage should be printed.
+     */
+    public Boolean help() {
+        return help != null ? help : Boolean.FALSE;
+    }
+
+    /**
+     * @param cfgUrl URL.
+     */
+    public void load(URL cfgUrl) throws IOException {
+        Properties props = new Properties();
+
+        try (Reader reader = new InputStreamReader(cfgUrl.openStream())) {
+            props.load(reader);
+        }
+
+        String val = (String)props.remove("tokens");
+
+        if (val != null)
+            tokens(Arrays.asList(val.split(",")));
+
+        val = (String)props.remove("server-uri");
+
+        if (val != null)
+            serverUri(val);
+
+        val = (String)props.remove("node-uri");
+
+        if (val != null)
+            nodeUri(val);
+
+        val = (String)props.remove("driver-folder");
+
+        if (val != null)
+            driversFolder(val);
+    }
+
+    /**
+     * @param cmd Command.
+     */
+    public void merge(AgentConfiguration cmd) {
+        if (tokens == null)
+            tokens(cmd.tokens());
+
+        if (srvUri == null)
+            serverUri(cmd.serverUri());
+
+        if (srvUri == null)
+            serverUri(DFLT_SERVER_URI);
+
+        if (nodeUri == null)
+            nodeUri(cmd.nodeUri());
+
+        if (nodeUri == null)
+            nodeUri(DFLT_NODE_URI);
+
+        if (driversFolder == null)
+            driversFolder(cmd.driversFolder());
+    }
+
+    /** {@inheritDoc} */
+    @Override public String toString() {
+        StringBuilder sb = new StringBuilder();
+
+        if (tokens != null && tokens.size() > 0) {
+            sb.append("User's security tokens        : ");
+
+            boolean first = true;
+
+            for (String tok : tokens) {
+                if (first)
+                    first = false;
+                else
+                    sb.append(",");
+
+                if (tok.length() > 4) {
+                    sb.append(new String(new char[tok.length() - 4]).replace('\0', '*'));
+
+                    sb.append(tok.substring(tok.length() - 4));
+                }
+                else
+                    sb.append(new String(new char[tok.length()]).replace('\0', '*'));
+            }
+
+            sb.append('\n');
+        }
+
+        sb.append("URI to Ignite node REST server: ").append(nodeUri == null ? DFLT_NODE_URI : nodeUri).append('\n');
+        sb.append("URI to Ignite Console server  : ").append(srvUri == null ? DFLT_SERVER_URI : srvUri).append('\n');
+        sb.append("Path to agent property file   : ").append(configPath()).append('\n');
+
+        String drvFld = driversFolder();
+
+        if (drvFld == null) {
+            File agentHome = AgentUtils.getAgentHome();
+
+            if (agentHome != null)
+                drvFld = new File(agentHome, "jdbc-drivers").getPath();
+        }
+
+        sb.append("Path to JDBC drivers folder   : ").append(drvFld);
+
+        return sb.toString();
+    }
+}

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/web-agent/src/main/java/org/apache/ignite/console/agent/AgentLauncher.java
----------------------------------------------------------------------
diff --git a/modules/web-console/web-agent/src/main/java/org/apache/ignite/console/agent/AgentLauncher.java b/modules/web-console/web-agent/src/main/java/org/apache/ignite/console/agent/AgentLauncher.java
new file mode 100644
index 0000000..810fad4
--- /dev/null
+++ b/modules/web-console/web-agent/src/main/java/org/apache/ignite/console/agent/AgentLauncher.java
@@ -0,0 +1,344 @@
+/*
+ * 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.
+ */
+
+package org.apache.ignite.console.agent;
+
+import com.beust.jcommander.JCommander;
+import com.beust.jcommander.ParameterException;
+import io.socket.client.Ack;
+import io.socket.client.IO;
+import io.socket.client.Socket;
+import io.socket.emitter.Emitter;
+import java.io.File;
+import java.io.IOException;
+import java.net.ConnectException;
+import java.net.URI;
+import java.net.URISyntaxException;
+import java.net.URL;
+import java.util.Arrays;
+import java.util.concurrent.CountDownLatch;
+import java.util.jar.Attributes;
+import java.util.jar.Manifest;
+import javax.net.ssl.SSLContext;
+import javax.net.ssl.SSLHandshakeException;
+import javax.net.ssl.TrustManager;
+import javax.net.ssl.X509TrustManager;
+import org.apache.ignite.console.agent.handlers.DatabaseHandler;
+import org.apache.ignite.console.agent.handlers.RestHandler;
+import org.apache.ignite.internal.util.typedef.X;
+import org.apache.log4j.Logger;
+import org.json.JSONException;
+import org.json.JSONObject;
+
+import static io.socket.client.Socket.EVENT_CONNECT;
+import static io.socket.client.Socket.EVENT_CONNECTING;
+import static io.socket.client.Socket.EVENT_CONNECT_ERROR;
+import static io.socket.client.Socket.EVENT_DISCONNECT;
+import static io.socket.client.Socket.EVENT_ERROR;
+import static io.socket.client.Socket.EVENT_RECONNECTING;
+import static org.apache.ignite.console.agent.AgentConfiguration.DFLT_SERVER_PORT;
+
+/**
+ * Control Center Agent launcher.
+ */
+public class AgentLauncher {
+    /** */
+    private static final Logger log = Logger.getLogger(AgentLauncher.class.getName());
+
+    /** */
+    private static final String EVENT_NODE_REST = "node:rest";
+
+    /** */
+    private static final String EVENT_SCHEMA_IMPORT_DRIVERS = "schemaImport:drivers";
+
+    /** */
+    private static final String EVENT_SCHEMA_IMPORT_SCHEMAS = "schemaImport:schemas";
+
+    /** */
+    private static final String EVENT_SCHEMA_IMPORT_METADATA = "schemaImport:metadata";
+
+    /** */
+    private static final String EVENT_AGENT_WARNING = "agent:warning";
+
+    /** */
+    private static final String EVENT_AGENT_CLOSE = "agent:close";
+
+    /** */
+    private static final int RECONNECT_INTERVAL = 3000;
+
+    /**
+     * Create a trust manager that trusts all certificates It is not using a particular keyStore
+     */
+    private static TrustManager[] getTrustManagers() {
+        return new TrustManager[] {
+            new X509TrustManager() {
+                public java.security.cert.X509Certificate[] getAcceptedIssuers() {
+                    return null;
+                }
+
+                public void checkClientTrusted(
+                    java.security.cert.X509Certificate[] certs, String authType) {
+                }
+
+                public void checkServerTrusted(
+                    java.security.cert.X509Certificate[] certs, String authType) {
+                }
+            }};
+    }
+
+    /**
+     * On error listener.
+     */
+    private static final Emitter.Listener onError = new Emitter.Listener() {
+        @SuppressWarnings("ThrowableResultOfMethodCallIgnored")
+        @Override public void call(Object... args) {
+            Throwable e = (Throwable)args[0];
+
+            ConnectException ce = X.cause(e, ConnectException.class);
+
+            if (ce != null)
+                log.error("Failed to receive response from server (connection refused).");
+            else {
+                Exception ignore = X.cause(e, SSLHandshakeException.class);
+
+                if (ignore != null) {
+                    log.error("Failed to establish SSL connection to server, due to errors with SSL handshake.");
+                    log.error("Add to environment variable JVM_OPTS parameter \"-Dtrust.all=true\" to skip certificate validation in case of using self-signed certificate.");
+
+                    System.exit(1);
+                }
+
+                ignore = X.cause(e, IOException.class);
+
+                if (ignore != null && "404".equals(ignore.getMessage())) {
+                    log.error("Failed to receive response from server (connection refused).");
+
+                    return;
+                }
+
+                log.error("Connection error.", e);
+            }
+        }
+    };
+
+    /**
+     * On disconnect listener.
+     */
+    private static final Emitter.Listener onDisconnect = new Emitter.Listener() {
+        @Override public void call(Object... args) {
+            log.error(String.format("Connection closed: %s.", args));
+        }
+    };
+
+    /**
+     * @param args Args.
+     */
+    @SuppressWarnings("BusyWait")
+    public static void main(String[] args) throws Exception {
+        log.info("Starting Apache Ignite Web Console Agent...");
+
+        final AgentConfiguration cfg = new AgentConfiguration();
+
+        JCommander jCommander = new JCommander(cfg);
+
+        String osName = System.getProperty("os.name").toLowerCase();
+
+        jCommander.setProgramName("ignite-web-agent." + (osName.contains("win") ? "bat" : "sh"));
+
+        try {
+            jCommander.parse(args);
+        }
+        catch (ParameterException pe) {
+            log.error("Failed to parse command line parameters: " + Arrays.toString(args), pe);
+
+            jCommander.usage();
+
+            return;
+        }
+
+        String prop = cfg.configPath();
+
+        AgentConfiguration propCfg = new AgentConfiguration();
+
+        try {
+            File f = AgentUtils.resolvePath(prop);
+
+            if (f == null)
+                log.warn("Failed to find agent property file: " + prop);
+            else
+                propCfg.load(f.toURI().toURL());
+        }
+        catch (IOException ignore) {
+            if (!AgentConfiguration.DFLT_CFG_PATH.equals(prop))
+                log.warn("Failed to load agent property file: " + prop, ignore);
+        }
+
+        cfg.merge(propCfg);
+
+        if (cfg.help()) {
+            jCommander.usage();
+
+            return;
+        }
+
+        System.out.println();
+        System.out.println("Agent configuration:");
+        System.out.println(cfg);
+        System.out.println();
+
+        if (cfg.tokens() == null) {
+            String webHost;
+
+            try {
+                webHost = new URI(cfg.serverUri()).getHost();
+            }
+            catch (URISyntaxException e) {
+                log.error("Failed to parse Ignite Web Console uri", e);
+
+                return;
+            }
+
+            System.out.println("Security token is required to establish connection to the web console.");
+            System.out.println(String.format("It is available on the Profile page: https://%s/profile", webHost));
+
+            System.out.print("Enter security tokens separated by comma: ");
+
+            cfg.tokens(Arrays.asList(System.console().readLine().trim().split(",")));
+        }
+
+        final RestHandler restHnd = new RestHandler(cfg);
+
+        try {
+            restHnd.start();
+
+            URI uri = URI.create(cfg.serverUri());
+
+            if (uri.getPort() == -1)
+                uri = URI.create(cfg.serverUri() + ':' + DFLT_SERVER_PORT);
+
+            IO.Options opts = new IO.Options();
+
+            opts.reconnectionDelay = RECONNECT_INTERVAL;
+
+            // Workaround for use self-signed certificate
+            if (Boolean.getBoolean("trust.all")) {
+                SSLContext ctx = SSLContext.getInstance("TLS");
+
+                // Create an SSLContext that uses our TrustManager
+                ctx.init(null, getTrustManagers(), null);
+
+                opts.sslContext = ctx;
+            }
+
+            final Socket client = IO.socket(uri, opts);
+
+            try {
+                Emitter.Listener onConnecting = new Emitter.Listener() {
+                    @Override public void call(Object... args) {
+                        log.info("Connecting to: " + cfg.serverUri());
+                    }
+                };
+
+                Emitter.Listener onConnect = new Emitter.Listener() {
+                    @Override public void call(Object... args) {
+                        log.info("Connection established.");
+
+                        JSONObject authMsg = new JSONObject();
+
+                        try {
+                            authMsg.put("tokens", cfg.tokens());
+
+                            String clsName = AgentLauncher.class.getSimpleName() + ".class";
+
+                            String clsPath = AgentLauncher.class.getResource(clsName).toString();
+
+                            if (clsPath.startsWith("jar")) {
+                                String manifestPath = clsPath.substring(0, clsPath.lastIndexOf('!') + 1) +
+                                    "/META-INF/MANIFEST.MF";
+
+                                Manifest manifest = new Manifest(new URL(manifestPath).openStream());
+
+                                Attributes attr = manifest.getMainAttributes();
+
+                                authMsg.put("ver", attr.getValue("Implementation-Version"));
+                                authMsg.put("bt", attr.getValue("Build-Time"));
+                            }
+
+                            client.emit("agent:auth", authMsg, new Ack() {
+                                @Override public void call(Object... args) {
+                                    // Authentication failed if response contains args.
+                                    if (args != null && args.length > 0) {
+                                        onDisconnect.call(args);
+
+                                        System.exit(1);
+                                    }
+
+                                    log.info("Authentication success.");
+                                }
+                            });
+                        }
+                        catch (JSONException | IOException e) {
+                            log.error("Failed to construct authentication message", e);
+
+                            client.close();
+                        }
+                    }
+                };
+
+                DatabaseHandler dbHnd = new DatabaseHandler(cfg);
+
+                final CountDownLatch latch = new CountDownLatch(1);
+
+                client
+                    .on(EVENT_CONNECTING, onConnecting)
+                    .on(EVENT_CONNECT, onConnect)
+                    .on(EVENT_CONNECT_ERROR, onError)
+                    .on(EVENT_RECONNECTING, onConnecting)
+                    .on(EVENT_NODE_REST, restHnd)
+                    .on(EVENT_SCHEMA_IMPORT_DRIVERS, dbHnd.availableDriversListener())
+                    .on(EVENT_SCHEMA_IMPORT_SCHEMAS, dbHnd.schemasListener())
+                    .on(EVENT_SCHEMA_IMPORT_METADATA, dbHnd.metadataListener())
+                    .on(EVENT_ERROR, onError)
+                    .on(EVENT_DISCONNECT, onDisconnect)
+                    .on(EVENT_AGENT_WARNING, new Emitter.Listener() {
+                        @Override public void call(Object... args) {
+                            log.warn(args[0]);
+                        }
+                    })
+                    .on(EVENT_AGENT_CLOSE, new Emitter.Listener() {
+                        @Override public void call(Object... args) {
+                            onDisconnect.call(args);
+
+                            client.off();
+
+                            latch.countDown();
+                        }
+                    });
+
+                client.connect();
+
+                latch.await();
+            }
+            finally {
+                client.close();
+            }
+        }
+        finally {
+            restHnd.stop();
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/web-agent/src/main/java/org/apache/ignite/console/agent/AgentUtils.java
----------------------------------------------------------------------
diff --git a/modules/web-console/web-agent/src/main/java/org/apache/ignite/console/agent/AgentUtils.java b/modules/web-console/web-agent/src/main/java/org/apache/ignite/console/agent/AgentUtils.java
new file mode 100644
index 0000000..50a849a
--- /dev/null
+++ b/modules/web-console/web-agent/src/main/java/org/apache/ignite/console/agent/AgentUtils.java
@@ -0,0 +1,111 @@
+/*
+ * 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.
+ */
+
+package org.apache.ignite.console.agent;
+
+import java.io.File;
+import java.net.URI;
+import java.net.URISyntaxException;
+import java.security.ProtectionDomain;
+import org.apache.log4j.Logger;
+
+/**
+ * Utility methods.
+ */
+public class AgentUtils {
+    /** */
+    private static final Logger log = Logger.getLogger(AgentUtils.class.getName());
+
+    /**
+     * Default constructor.
+     */
+    private AgentUtils() {
+        // No-op.
+    }
+
+    /**
+     * @param path Path to normalize.
+     * @return Normalized file path.
+     */
+    public static String normalizePath(String path) {
+        return path != null ? path.replace('\\', '/') : null;
+    }
+
+    /**
+     * @return App folder.
+     */
+    public static File getAgentHome() {
+        try {
+            ProtectionDomain domain = AgentLauncher.class.getProtectionDomain();
+
+            // Should not happen, but to make sure our code is not broken.
+            if (domain == null || domain.getCodeSource() == null || domain.getCodeSource().getLocation() == null) {
+                log.warn("Failed to resolve agent jar location!");
+
+                return null;
+            }
+
+            // Resolve path to class-file.
+            URI classesUri = domain.getCodeSource().getLocation().toURI();
+
+            boolean win = System.getProperty("os.name").toLowerCase().contains("win");
+
+            // Overcome UNC path problem on Windows (http://www.tomergabel.com/JavaMishandlesUNCPathsOnWindows.aspx)
+            if (win && classesUri.getAuthority() != null)
+                classesUri = new URI(classesUri.toString().replace("file://", "file:/"));
+
+            return new File(classesUri).getParentFile();
+        }
+        catch (URISyntaxException | SecurityException ignored) {
+            log.warn("Failed to resolve agent jar location!");
+
+            return null;
+        }
+    }
+
+    /**
+     * Gets file associated with path.
+     * <p>
+     * First check if path is relative to agent home.
+     * If not, check if path is absolute.
+     * If all checks fail, then {@code null} is returned.
+     * <p>
+     *
+     * @param path Path to resolve.
+     * @return Resolved path as file, or {@code null} if path cannot be resolved.
+     */
+    public static File resolvePath(String path) {
+        assert path != null;
+
+        File home = getAgentHome();
+
+        if (home != null) {
+            File file = new File(home, normalizePath(path));
+
+            if (file.exists())
+                return file;
+        }
+
+        // 2. Check given path as absolute.
+        File file = new File(path);
+
+        if (file.exists())
+            return file;
+
+        return null;
+    }
+}

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/web-agent/src/main/java/org/apache/ignite/console/agent/handlers/AbstractHandler.java
----------------------------------------------------------------------
diff --git a/modules/web-console/web-agent/src/main/java/org/apache/ignite/console/agent/handlers/AbstractHandler.java b/modules/web-console/web-agent/src/main/java/org/apache/ignite/console/agent/handlers/AbstractHandler.java
new file mode 100644
index 0000000..7e4e320
--- /dev/null
+++ b/modules/web-console/web-agent/src/main/java/org/apache/ignite/console/agent/handlers/AbstractHandler.java
@@ -0,0 +1,110 @@
+/*
+ * 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.
+ */
+
+package org.apache.ignite.console.agent.handlers;
+
+import com.fasterxml.jackson.annotation.JsonAutoDetect;
+import com.fasterxml.jackson.annotation.PropertyAccessor;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import com.fasterxml.jackson.datatype.jsonorg.JsonOrgModule;
+import io.socket.client.Ack;
+import io.socket.emitter.Emitter;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.Map;
+import org.json.JSONArray;
+import org.json.JSONObject;
+
+/**
+ * Base class for web socket handlers.
+ */
+abstract class AbstractHandler implements Emitter.Listener {
+    /** JSON object mapper. */
+    private static final ObjectMapper mapper = new ObjectMapper();
+
+    static {
+        JsonOrgModule module = new JsonOrgModule();
+
+        mapper.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.NONE);
+        mapper.setVisibility(PropertyAccessor.FIELD, JsonAutoDetect.Visibility.ANY);
+
+        mapper.registerModule(module);
+    }
+
+    /**
+     * @param obj Object.
+     * @return {@link JSONObject} or {@link JSONArray}.
+     */
+    private Object toJSON(Object obj) {
+        if (obj instanceof Iterable)
+            return mapper.convertValue(obj, JSONArray.class);
+
+        return mapper.convertValue(obj, JSONObject.class);
+    }
+
+    /** {@inheritDoc} */
+    @SuppressWarnings("unchecked")
+    @Override public final void call(Object... args) {
+        Ack cb = null;
+
+        try {
+            if (args == null || args.length == 0)
+                throw new IllegalArgumentException("Missing arguments.");
+
+            if (args.length > 2)
+                throw new IllegalArgumentException("Wrong arguments count, must be <= 2: " + Arrays.toString(args));
+
+            JSONObject lsnrArgs = null;
+
+            if (args.length == 1) {
+                if (args[0] instanceof JSONObject)
+                    lsnrArgs = (JSONObject)args[0];
+                else if (args[0] instanceof Ack)
+                    cb = (Ack)args[0];
+                else
+                    throw new IllegalArgumentException("Wrong type of argument, must be JSONObject or Ack: " + args[0]);
+            }
+            else {
+                if (args[0] != null && !(args[0] instanceof JSONObject))
+                    throw new IllegalArgumentException("Wrong type of argument, must be JSONObject: " + args[0]);
+
+                if (!(args[1] instanceof Ack))
+                    throw new IllegalArgumentException("Wrong type of argument, must be Ack: " + args[1]);
+
+                lsnrArgs = (JSONObject)args[0];
+
+                cb = (Ack)args[1];
+            }
+
+            Object res = execute(lsnrArgs == null ? Collections.emptyMap() : mapper.convertValue(lsnrArgs, Map.class));
+
+            if (cb != null)
+                cb.call(null, toJSON(res));
+        }
+        catch (Exception e) {
+            if (cb != null)
+                cb.call(e, null);
+        }
+    }
+
+    /**
+     * Execute command with specified arguments.
+     *
+     * @param args Map with method args.
+     */
+    public abstract Object execute(Map<String, Object> args) throws Exception;
+}

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/web-agent/src/main/java/org/apache/ignite/console/agent/handlers/DatabaseHandler.java
----------------------------------------------------------------------
diff --git a/modules/web-console/web-agent/src/main/java/org/apache/ignite/console/agent/handlers/DatabaseHandler.java b/modules/web-console/web-agent/src/main/java/org/apache/ignite/console/agent/handlers/DatabaseHandler.java
new file mode 100644
index 0000000..02146d9
--- /dev/null
+++ b/modules/web-console/web-agent/src/main/java/org/apache/ignite/console/agent/handlers/DatabaseHandler.java
@@ -0,0 +1,298 @@
+/*
+ * 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.
+ */
+
+package org.apache.ignite.console.agent.handlers;
+
+import io.socket.emitter.Emitter;
+import java.io.BufferedReader;
+import java.io.File;
+import java.io.FilenameFilter;
+import java.io.IOException;
+import java.io.InputStreamReader;
+import java.net.URL;
+import java.sql.Connection;
+import java.sql.SQLException;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.List;
+import java.util.Map;
+import java.util.Properties;
+import org.apache.ignite.console.agent.AgentConfiguration;
+import org.apache.ignite.console.demo.AgentMetadataDemo;
+import org.apache.ignite.schema.parser.DbMetadataReader;
+import org.apache.ignite.schema.parser.DbTable;
+import org.apache.log4j.Logger;
+
+import static org.apache.ignite.console.agent.AgentUtils.resolvePath;
+
+/**
+ * API to extract database metadata.
+ */
+public class DatabaseHandler {
+    /** */
+    private static final Logger log = Logger.getLogger(DatabaseHandler.class.getName());
+
+    /** */
+    private final File driversFolder;
+
+    /**
+     * @param cfg Config.
+     */
+    public DatabaseHandler(AgentConfiguration cfg) {
+        driversFolder = resolvePath(cfg.driversFolder() == null ? "jdbc-drivers" : cfg.driversFolder());
+    }
+
+    /**
+     * @param jdbcDriverJarPath JDBC driver JAR path.
+     * @param jdbcDriverCls JDBC driver class.
+     * @param jdbcUrl JDBC URL.
+     * @param jdbcInfo Properties to connect to database.
+     * @return Connection to database.
+     * @throws SQLException
+     */
+    private Connection connect(String jdbcDriverJarPath, String jdbcDriverCls, String jdbcUrl,
+        Properties jdbcInfo) throws SQLException {
+        if (AgentMetadataDemo.isTestDriveUrl(jdbcUrl))
+            return AgentMetadataDemo.testDrive();
+
+        if (!new File(jdbcDriverJarPath).isAbsolute() && driversFolder != null)
+            jdbcDriverJarPath = new File(driversFolder, jdbcDriverJarPath).getPath();
+
+        return DbMetadataReader.getInstance().connect(jdbcDriverJarPath, jdbcDriverCls, jdbcUrl, jdbcInfo);
+    }
+
+    /**
+     * @param jdbcDriverJarPath JDBC driver JAR path.
+     * @param jdbcDriverCls JDBC driver class.
+     * @param jdbcUrl JDBC URL.
+     * @param jdbcInfo Properties to connect to database.
+     * @return Collection of schema names.
+     * @throws SQLException
+     */
+    protected Collection<String> schemas(String jdbcDriverJarPath, String jdbcDriverCls, String jdbcUrl,
+        Properties jdbcInfo) throws SQLException {
+        if (log.isDebugEnabled())
+            log.debug("Start collecting database schemas [drvJar=" + jdbcDriverJarPath +
+                ", drvCls=" + jdbcDriverCls + ", jdbcUrl=" + jdbcUrl + "]");
+
+        try (Connection conn = connect(jdbcDriverJarPath, jdbcDriverCls, jdbcUrl, jdbcInfo)) {
+            Collection<String> schemas = DbMetadataReader.getInstance().schemas(conn);
+
+            if (log.isDebugEnabled())
+                log.debug("Finished collection of schemas [jdbcUrl=" + jdbcUrl + ", count=" + schemas.size() + "]");
+
+            return schemas;
+        }
+        catch (Throwable e) {
+            log.error("Failed to collect schemas", e);
+
+            throw new SQLException("Failed to collect schemas", e);
+        }
+    }
+
+    /**
+     * Listener for schema names.
+     *
+     * @return Collection of schema names.
+     */
+    public Emitter.Listener schemasListener() {
+        return new AbstractHandler() {
+            @Override public Object execute(Map<String, Object> args) throws Exception {
+                String driverPath = null;
+
+                if (args.containsKey("driverPath"))
+                    driverPath = args.get("driverPath").toString();
+
+                if (!args.containsKey("driverClass"))
+                    throw new IllegalArgumentException("Missing driverClass in arguments: " + args);
+
+                String driverCls = args.get("driverClass").toString();
+
+                if (!args.containsKey("url"))
+                    throw new IllegalArgumentException("Missing url in arguments: " + args);
+
+                String url = args.get("url").toString();
+
+                if (!args.containsKey("info"))
+                    throw new IllegalArgumentException("Missing info in arguments: " + args);
+
+                Properties info = new Properties();
+
+                info.putAll((Map)args.get("info"));
+
+                return schemas(driverPath, driverCls, url, info);
+            }
+        };
+    }
+
+    /**
+     * @param jdbcDriverJarPath JDBC driver JAR path.
+     * @param jdbcDriverCls JDBC driver class.
+     * @param jdbcUrl JDBC URL.
+     * @param jdbcInfo Properties to connect to database.
+     * @param schemas List of schema names to process.
+     * @param tblsOnly If {@code true} then only tables will be processed otherwise views also will be processed.
+     * @return Collection of tables.
+     */
+    protected Collection<DbTable> metadata(String jdbcDriverJarPath, String jdbcDriverCls, String jdbcUrl,
+        Properties jdbcInfo, List<String> schemas, boolean tblsOnly) throws SQLException {
+        if (log.isDebugEnabled())
+            log.debug("Start collecting database metadata [drvJar=" + jdbcDriverJarPath +
+                ", drvCls=" + jdbcDriverCls + ", jdbcUrl=" + jdbcUrl + "]");
+
+        try (Connection conn = connect(jdbcDriverJarPath, jdbcDriverCls, jdbcUrl, jdbcInfo)) {
+            Collection<DbTable> metadata = DbMetadataReader.getInstance().metadata(conn, schemas, tblsOnly);
+
+            if (log.isDebugEnabled())
+                log.debug("Finished collection of metadata [jdbcUrl=" + jdbcUrl + ", count=" + metadata.size() + "]");
+
+            return metadata;
+        }
+        catch (Throwable e) {
+            log.error("Failed to collect metadata", e);
+
+            throw new SQLException("Failed to collect metadata", e);
+        }
+    }
+
+    /**
+     * Listener for tables.
+     *
+     * @return Collection of tables.
+     */
+    public Emitter.Listener metadataListener() {
+        return new AbstractHandler() {
+            @SuppressWarnings("unchecked")
+            @Override public Object execute(Map<String, Object> args) throws Exception {
+                String driverPath = null;
+
+                if (args.containsKey("driverPath"))
+                    driverPath = args.get("driverPath").toString();
+
+                if (!args.containsKey("driverClass"))
+                    throw new IllegalArgumentException("Missing driverClass in arguments: " + args);
+
+                String driverCls = args.get("driverClass").toString();
+
+                if (!args.containsKey("url"))
+                    throw new IllegalArgumentException("Missing url in arguments: " + args);
+
+                String url = args.get("url").toString();
+
+                if (!args.containsKey("info"))
+                    throw new IllegalArgumentException("Missing info in arguments: " + args);
+
+                Properties info = new Properties();
+
+                info.putAll((Map)args.get("info"));
+
+                if (!args.containsKey("schemas"))
+                    throw new IllegalArgumentException("Missing schemas in arguments: " + args);
+
+                List<String> schemas = (List<String>)args.get("schemas");
+
+                if (!args.containsKey("tablesOnly"))
+                    throw new IllegalArgumentException("Missing tablesOnly in arguments: " + args);
+
+                boolean tblsOnly = (boolean)args.get("tablesOnly");
+
+                return metadata(driverPath, driverCls, url, info, schemas, tblsOnly);
+            }
+        };
+    }
+
+    /**
+     * Listener for drivers.
+     *
+     * @return Drivers in drivers folder
+     * @see AgentConfiguration#driversFolder
+     */
+    public Emitter.Listener availableDriversListener() {
+        return new AbstractHandler() {
+            @Override public Object execute(Map<String, Object> args) throws Exception {
+                if (driversFolder == null) {
+                    log.info("JDBC drivers folder not specified, returning empty list");
+
+                    return Collections.emptyList();
+                }
+
+                if (log.isDebugEnabled())
+                    log.debug("Collecting JDBC drivers in folder: " + driversFolder.getPath());
+
+                File[] list = driversFolder.listFiles(new FilenameFilter() {
+                    @Override public boolean accept(File dir, String name) {
+                        return name.endsWith(".jar");
+                    }
+                });
+
+                if (list == null) {
+                    log.info("JDBC drivers folder has no files, returning empty list");
+
+                    return Collections.emptyList();
+                }
+
+                List<JdbcDriver> res = new ArrayList<>();
+
+                for (File file : list) {
+                    try {
+                        boolean win = System.getProperty("os.name").contains("win");
+
+                        URL url = new URL("jar", null,
+                            "file:" + (win ? "/" : "") + file.getPath() + "!/META-INF/services/java.sql.Driver");
+
+                        try (BufferedReader reader = new BufferedReader(new InputStreamReader(url.openStream()))) {
+                            String jdbcDriverCls = reader.readLine();
+
+                            res.add(new JdbcDriver(file.getName(), jdbcDriverCls));
+
+                            if (log.isDebugEnabled())
+                                log.debug("Found: [driver=" + file + ", class=" + jdbcDriverCls + "]");
+                        }
+                    }
+                    catch (IOException e) {
+                        res.add(new JdbcDriver(file.getName(), null));
+
+                        log.info("Found: [driver=" + file + "]");
+                        log.info("Failed to detect driver class: " + e.getMessage());
+                    }
+                }
+
+                return res;
+            }
+        };
+    }
+
+    /**
+     * Wrapper class for later to be transformed to JSON and send to Web Console.
+     */
+    private static class JdbcDriver {
+        /** */
+        public final String jdbcDriverJar;
+        /** */
+        public final String jdbcDriverCls;
+
+        /**
+         * @param jdbcDriverJar File name of driver jar file.
+         * @param jdbcDriverCls Optional JDBC driver class.
+         */
+        public JdbcDriver(String jdbcDriverJar, String jdbcDriverCls) {
+            this.jdbcDriverJar = jdbcDriverJar;
+            this.jdbcDriverCls = jdbcDriverCls;
+        }
+    }
+}


[31/52] ignite git commit: Web Console beta-3.

Posted by ak...@apache.org.
http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/frontend/app/services/FormUtils.service.js
----------------------------------------------------------------------
diff --git a/modules/web-console/frontend/app/services/FormUtils.service.js b/modules/web-console/frontend/app/services/FormUtils.service.js
new file mode 100644
index 0000000..5e7943a
--- /dev/null
+++ b/modules/web-console/frontend/app/services/FormUtils.service.js
@@ -0,0 +1,435 @@
+/*
+ * 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 ['IgniteFormUtils', ['$window', 'IgniteFocus', ($window, Focus) => {
+    function ensureActivePanel(ui, pnl, focusId) {
+        if (ui) {
+            const collapses = $('div.panel-collapse');
+
+            ui.loadPanel(pnl);
+
+            const idx = _.findIndex(collapses, function(collapse) {
+                return collapse.id === pnl;
+            });
+
+            if (idx >= 0) {
+                const activePanels = ui.activePanels;
+
+                if (!_.includes(ui.topPanels, idx)) {
+                    ui.expanded = true;
+
+                    const customExpanded = ui[pnl];
+
+                    if (customExpanded)
+                        ui[customExpanded] = true;
+                }
+
+                if (!activePanels || activePanels.length < 1)
+                    ui.activePanels = [idx];
+                else if (!_.includes(activePanels, idx)) {
+                    const newActivePanels = angular.copy(activePanels);
+
+                    newActivePanels.push(idx);
+
+                    ui.activePanels = newActivePanels;
+                }
+            }
+
+            if (!_.isNil(focusId))
+                Focus.move(focusId);
+        }
+    }
+
+    let context = null;
+
+    /**
+     * Calculate width of specified text in body's font.
+     *
+     * @param text Text to calculate width.
+     * @returns {Number} Width of text in pixels.
+     */
+    function measureText(text) {
+        if (!context) {
+            const canvas = document.createElement('canvas');
+
+            context = canvas.getContext('2d');
+
+            const style = window.getComputedStyle(document.getElementsByTagName('body')[0]);
+
+            context.font = style.fontSize + ' ' + style.fontFamily;
+        }
+
+        return context.measureText(text).width;
+    }
+
+    /**
+     * Compact java full class name by max number of characters.
+     *
+     * @param names Array of class names to compact.
+     * @param nameLength Max available width in characters for simple name.
+     * @returns {*} Array of compacted class names.
+     */
+    function compactByMaxCharts(names, nameLength) {
+        for (let nameIx = 0; nameIx < names.length; nameIx++) {
+            const s = names[nameIx];
+
+            if (s.length > nameLength) {
+                let totalLength = s.length;
+
+                const packages = s.split('.');
+
+                const packageCnt = packages.length - 1;
+
+                for (let i = 0; i < packageCnt && totalLength > nameLength; i++) {
+                    if (packages[i].length > 0) {
+                        totalLength -= packages[i].length - 1;
+
+                        packages[i] = packages[i][0];
+                    }
+                }
+
+                if (totalLength > nameLength) {
+                    const className = packages[packageCnt];
+
+                    const classNameLen = className.length;
+
+                    let remains = Math.min(nameLength - totalLength + classNameLen, classNameLen);
+
+                    if (remains < 3)
+                        remains = Math.min(3, classNameLen);
+
+                    packages[packageCnt] = className.substring(0, remains) + '...';
+                }
+
+                let result = packages[0];
+
+                for (let i = 1; i < packages.length; i++)
+                    result += '.' + packages[i];
+
+                names[nameIx] = result;
+            }
+        }
+
+        return names;
+    }
+
+    /**
+     * Compact java full class name by max number of pixels.
+     *
+     * @param names Array of class names to compact.
+     * @param nameLength Max available width in characters for simple name. Used for calculation optimization.
+     * @param nameWidth Maximum available width in pixels for simple name.
+     * @returns {*} Array of compacted class names.
+     */
+    function compactByMaxPixels(names, nameLength, nameWidth) {
+        if (nameWidth <= 0)
+            return names;
+
+        const fitted = [];
+
+        const widthByName = [];
+
+        const len = names.length;
+
+        let divideTo = len;
+
+        for (let nameIx = 0; nameIx < len; nameIx++) {
+            fitted[nameIx] = false;
+
+            widthByName[nameIx] = nameWidth;
+        }
+
+        // Try to distribute space from short class names to long class names.
+        let remains = 0;
+
+        do {
+            for (let nameIx = 0; nameIx < len; nameIx++) {
+                if (!fitted[nameIx]) {
+                    const curNameWidth = measureText(names[nameIx]);
+
+                    if (widthByName[nameIx] > curNameWidth) {
+                        fitted[nameIx] = true;
+
+                        remains += widthByName[nameIx] - curNameWidth;
+
+                        divideTo -= 1;
+
+                        widthByName[nameIx] = curNameWidth;
+                    }
+                }
+            }
+
+            const remainsByName = remains / divideTo;
+
+            for (let nameIx = 0; nameIx < len; nameIx++) {
+                if (!fitted[nameIx])
+                    widthByName[nameIx] += remainsByName;
+            }
+        }
+        while (remains > 0);
+
+        // Compact class names to available for each space.
+        for (let nameIx = 0; nameIx < len; nameIx++) {
+            const s = names[nameIx];
+
+            if (s.length > (nameLength / 2 | 0)) {
+                let totalWidth = measureText(s);
+
+                if (totalWidth > widthByName[nameIx]) {
+                    const packages = s.split('.');
+
+                    const packageCnt = packages.length - 1;
+
+                    for (let i = 0; i < packageCnt && totalWidth > widthByName[nameIx]; i++) {
+                        if (packages[i].length > 1) {
+                            totalWidth -= measureText(packages[i].substring(1, packages[i].length));
+
+                            packages[i] = packages[i][0];
+                        }
+                    }
+
+                    let shortPackage = '';
+
+                    for (let i = 0; i < packageCnt; i++)
+                        shortPackage += packages[i] + '.';
+
+                    const className = packages[packageCnt];
+
+                    const classLen = className.length;
+
+                    let minLen = Math.min(classLen, 3);
+
+                    totalWidth = measureText(shortPackage + className);
+
+                    // Compact class name if shorten package path is very long.
+                    if (totalWidth > widthByName[nameIx]) {
+                        let maxLen = classLen;
+                        let middleLen = (minLen + (maxLen - minLen) / 2 ) | 0;
+
+                        while (middleLen !== minLen && middleLen !== maxLen) {
+                            const middleLenPx = measureText(shortPackage + className.substr(0, middleLen) + '...');
+
+                            if (middleLenPx > widthByName[nameIx])
+                                maxLen = middleLen;
+                            else
+                                minLen = middleLen;
+
+                            middleLen = (minLen + (maxLen - minLen) / 2 ) | 0;
+                        }
+
+                        names[nameIx] = shortPackage + className.substring(0, middleLen) + '...';
+                    }
+                    else
+                        names[nameIx] = shortPackage + className;
+                }
+            }
+        }
+
+        return names;
+    }
+
+    /**
+     * Compact any string by max number of pixels.
+     *
+     * @param label String to compact.
+     * @param nameWidth Maximum available width in pixels for simple name.
+     * @returns {*} Compacted string.
+     */
+    function compactLabelByPixels(label, nameWidth) {
+        if (nameWidth <= 0)
+            return label;
+
+        const totalWidth = measureText(label);
+
+        if (totalWidth > nameWidth) {
+            let maxLen = label.length;
+            let minLen = Math.min(maxLen, 3);
+            let middleLen = (minLen + (maxLen - minLen) / 2 ) | 0;
+
+            while (middleLen !== minLen && middleLen !== maxLen) {
+                const middleLenPx = measureText(label.substr(0, middleLen) + '...');
+
+                if (middleLenPx > nameWidth)
+                    maxLen = middleLen;
+                else
+                    minLen = middleLen;
+
+                middleLen = (minLen + (maxLen - minLen) / 2 ) | 0;
+            }
+
+            return label.substring(0, middleLen) + '...';
+        }
+
+        return label;
+    }
+
+    /**
+     * Calculate available width for text in link to edit element.
+     *
+     * @param index Showed index of element for calculation of maximum width in pixels.
+     * @param id Id of contains link table.
+     * @returns {*[]} First element is length of class for single value, second element is length for pair vlaue.
+     */
+    function availableWidth(index, id) {
+        const idElem = $('#' + id);
+
+        let width = 0;
+
+        switch (idElem.prop('tagName')) {
+            // Detection of available width in presentation table row.
+            case 'TABLE':
+                const cont = $(idElem.find('tr')[index - 1]).find('td')[0];
+
+                width = cont.clientWidth;
+
+                if (width > 0) {
+                    const children = $(cont).children(':not("a")');
+
+                    _.forEach(children, function(child) {
+                        if ('offsetWidth' in child)
+                            width -= $(child).outerWidth(true);
+                    });
+                }
+
+                break;
+
+            // Detection of available width in dropdown row.
+            case 'A':
+                width = idElem.width();
+
+                $(idElem).children(':not("span")').each(function(ix, child) {
+                    if ('offsetWidth' in child)
+                        width -= child.offsetWidth;
+                });
+
+                break;
+
+            default:
+        }
+
+        return width | 0;
+    }
+
+    return {
+        /**
+         * Cut class name by width in pixel or width in symbol count.
+         *
+         * @param id Id of parent table.
+         * @param index Row number in table.
+         * @param maxLength Maximum length in symbols for all names.
+         * @param names Array of class names to compact.
+         * @param divider String to visualy divide items.
+         * @returns {*} Array of compacted class names.
+         */
+        compactJavaName(id, index, maxLength, names, divider) {
+            divider = ' ' + divider + ' ';
+
+            const prefix = index + ') ';
+
+            const nameCnt = names.length;
+
+            const nameLength = ((maxLength - 3 * (nameCnt - 1)) / nameCnt) | 0;
+
+            try {
+                const nameWidth = (availableWidth(index, id) - measureText(prefix) - (nameCnt - 1) * measureText(divider)) /
+                    nameCnt | 0;
+
+                // HTML5 calculation of showed message width.
+                names = compactByMaxPixels(names, nameLength, nameWidth);
+            }
+            catch (err) {
+                names = compactByMaxCharts(names, nameLength);
+            }
+
+            let result = prefix + names[0];
+
+            for (let nameIx = 1; nameIx < names.length; nameIx++)
+                result += divider + names[nameIx];
+
+            return result;
+        },
+        /**
+         * Compact text by width in pixels or symbols count.
+         *
+         * @param id Id of parent table.
+         * @param index Row number in table.
+         * @param maxLength Maximum length in symbols for all names.
+         * @param label Text to compact.
+         * @returns Compacted label text.
+         */
+        compactTableLabel(id, index, maxLength, label) {
+            label = index + ') ' + label;
+
+            try {
+                const nameWidth = availableWidth(index, id) | 0;
+
+                // HTML5 calculation of showed message width.
+                label = compactLabelByPixels(label, nameWidth);
+            }
+            catch (err) {
+                const nameLength = maxLength - 3 | 0;
+
+                label = label.length > maxLength ? label.substr(0, nameLength) + '...' : label;
+            }
+
+            return label;
+        },
+        widthIsSufficient(id, index, text) {
+            try {
+                const available = availableWidth(index, id);
+
+                const required = measureText(text);
+
+                return !available || available >= Math.floor(required);
+            }
+            catch (err) {
+                return true;
+            }
+        },
+        ensureActivePanel(panels, id, focusId) {
+            ensureActivePanel(panels, id, focusId);
+        },
+        confirmUnsavedChanges(dirty, selectFunc) {
+            if (dirty) {
+                if ($window.confirm('You have unsaved changes.\n\nAre you sure you want to discard them?'))
+                    selectFunc();
+            }
+            else
+                selectFunc();
+        },
+        saveBtnTipText(dirty, objectName) {
+            if (dirty)
+                return 'Save ' + objectName;
+
+            return 'Nothing to save';
+        },
+        formUI() {
+            return {
+                ready: false,
+                expanded: false,
+                loadedPanels: [],
+                loadPanel(pnl) {
+                    if (!_.includes(this.loadedPanels, pnl))
+                        this.loadedPanels.push(pnl);
+                },
+                isPanelLoaded(pnl) {
+                    return _.includes(this.loadedPanels, pnl);
+                }
+            };
+        }
+    };
+}]];

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/frontend/app/services/InetAddress.service.js
----------------------------------------------------------------------
diff --git a/modules/web-console/frontend/app/services/InetAddress.service.js b/modules/web-console/frontend/app/services/InetAddress.service.js
new file mode 100644
index 0000000..abdd8a3
--- /dev/null
+++ b/modules/web-console/frontend/app/services/InetAddress.service.js
@@ -0,0 +1,53 @@
+/*
+ * 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 ['IgniteInetAddress', function() {
+    return {
+        /**
+         * @param {String} ip IP address to check.
+         * @returns {boolean} 'true' if given ip address is valid.
+         */
+        validIp(ip) {
+            const regexp = /^(([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])$/;
+
+            return regexp.test(ip);
+        },
+        /**
+         * @param {String} hostNameOrIp host name or ip address to check.
+         * @returns {boolean} 'true' if given is host name or ip.
+         */
+        validHost(hostNameOrIp) {
+            const regexp = /^(([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 regexp.test(hostNameOrIp) || this.validIp(hostNameOrIp);
+        },
+        /**
+         * @param {int} port Port value to check.
+         * @returns boolean 'true' if given port is valid tcp/udp port range.
+         */
+        validPort(port) {
+            return _.isInteger(port) && port > 0 && port <= 65535;
+        },
+        /**
+         * @param {int} port Port value to check.
+         * @returns {boolean} 'true' if given port in non system port range(user+dynamic).
+         */
+        validNonSystemPort(port) {
+            return _.isInteger(port) && port >= 1024 && port <= 65535;
+        }
+    };
+}];

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/frontend/app/services/JavaTypes.service.js
----------------------------------------------------------------------
diff --git a/modules/web-console/frontend/app/services/JavaTypes.service.js b/modules/web-console/frontend/app/services/JavaTypes.service.js
new file mode 100644
index 0000000..e8d4903
--- /dev/null
+++ b/modules/web-console/frontend/app/services/JavaTypes.service.js
@@ -0,0 +1,93 @@
+/*
+ * 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.
+ */
+
+// Java built-in class names.
+import JAVA_CLASSES from '../data/java-classes.json';
+
+// Java build-in primitive.
+import JAVA_PRIMITIVES from '../data/java-primitives.json';
+
+import JAVA_KEYWORDS from '../data/java-keywords.json';
+
+export default ['JavaTypes', function() {
+    return {
+        /**
+         * @param {String} clsName Class name to check.
+         * @returns boolean 'true' if given class name non a Java built-in type.
+         */
+        nonBuiltInClass(clsName) {
+            return _.isNil(_.find(JAVA_CLASSES, (clazz) => clsName === clazz.short || clsName === clazz.full));
+        },
+        /**
+         * @param clsName Class name to check.
+         * @returns Full class name for java build-in types or source class otherwise.
+         */
+        fullClassName(clsName) {
+            const type = _.find(JAVA_CLASSES, (clazz) => clsName === clazz.short);
+
+            return type ? type.full : clsName;
+        },
+        /**
+         * @param {String} value text to check.
+         * @returns boolean 'true' if given text is valid Java identifier.
+         */
+        validIdentifier(value) {
+            const regexp = /^(([a-zA-Z_$][a-zA-Z0-9_$]*)\.)*([a-zA-Z_$][a-zA-Z0-9_$]*)$/igm;
+
+            return value === '' || regexp.test(value);
+        },
+        /**
+         * @param {String} value text to check.
+         * @returns boolean 'true' if given text is valid Java package.
+         */
+        validPackage(value) {
+            const regexp = /^(([a-zA-Z_$][a-zA-Z0-9_$]*)\.)*([a-zA-Z_$][a-zA-Z0-9_$]*(\.?\*)?)$/igm;
+
+            return value === '' || regexp.test(value);
+        },
+        /**
+         * @param {String} value text to check.
+         * @returns boolean 'true' if given text is valid Java UUID value.
+         */
+        validUUID(value) {
+            const regexp = /^[0-9a-f]{8}-[0-9a-f]{4}-[1-5][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/igm;
+
+            return value === '' || regexp.test(value);
+        },
+        /**
+         * @param {String} value text to check.
+         * @returns boolean 'true' if given text is a Java type with package.
+         */
+        packageSpecified(value) {
+            return value.split('.').length >= 2;
+        },
+        /**
+         * @param {String} value text to check.
+         * @returns boolean 'true' if given text non Java keyword.
+         */
+        isKeywords(value) {
+            return _.includes(JAVA_KEYWORDS, value);
+        },
+        /**
+         * @param {String} clsName Class name to check.
+         * @returns {boolean} 'true' if givent class name is java primitive.
+         */
+        isJavaPrimitive(clsName) {
+            return _.includes(JAVA_PRIMITIVES, clsName);
+        }
+    };
+}];

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/frontend/app/services/LegacyTable.service.js
----------------------------------------------------------------------
diff --git a/modules/web-console/frontend/app/services/LegacyTable.service.js b/modules/web-console/frontend/app/services/LegacyTable.service.js
new file mode 100644
index 0000000..5d9ec9d
--- /dev/null
+++ b/modules/web-console/frontend/app/services/LegacyTable.service.js
@@ -0,0 +1,209 @@
+/*
+ * 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.
+ */
+
+// TODO: Refactor this service for legacy tables with more than one input field.
+export default ['IgniteLegacyTable',
+    ['IgniteLegacyUtils', 'IgniteFocus', 'IgniteErrorPopover', (LegacyUtils, Focus, ErrorPopover) => {
+        function _model(item, field) {
+            return LegacyUtils.getModel(item, field);
+        }
+
+        const table = {name: 'none', editIndex: -1};
+
+        function _tableReset() {
+            delete table.field;
+            table.name = 'none';
+            table.editIndex = -1;
+
+            ErrorPopover.hide();
+        }
+
+        function _tableSaveAndReset() {
+            const field = table.field;
+
+            const save = LegacyUtils.isDefined(field) && LegacyUtils.isDefined(field.save);
+
+            if (!save || !LegacyUtils.isDefined(field) || field.save(field, table.editIndex, true)) {
+                _tableReset();
+
+                return true;
+            }
+
+            return false;
+        }
+
+        function _tableState(field, editIndex, specName) {
+            table.field = field;
+            table.name = specName || field.model;
+            table.editIndex = editIndex;
+        }
+
+        function _tableUI(field) {
+            const ui = field.ui;
+
+            return ui ? ui : field.type;
+        }
+
+        function _tableFocus(focusId, index) {
+            Focus.move((index < 0 ? 'new' : 'cur') + focusId + (index >= 0 ? index : ''));
+        }
+
+        function _tablePairValue(filed, index) {
+            return index < 0 ? {key: filed.newKey, value: filed.newValue} : {
+                key: filed.curKey,
+                value: filed.curValue
+            };
+        }
+
+        function _tableStartEdit(item, tbl, index, save) {
+            _tableState(tbl, index);
+
+            const val = _.get(_model(item, tbl), tbl.model)[index];
+
+            const ui = _tableUI(tbl);
+
+            tbl.save = save;
+
+            if (ui === 'table-pair') {
+                tbl.curKey = val[tbl.keyName];
+                tbl.curValue = val[tbl.valueName];
+
+                _tableFocus('Key' + tbl.focusId, index);
+            }
+            else if (ui === 'table-db-fields') {
+                tbl.curDatabaseFieldName = val.databaseFieldName;
+                tbl.curDatabaseFieldType = val.databaseFieldType;
+                tbl.curJavaFieldName = val.javaFieldName;
+                tbl.curJavaFieldType = val.javaFieldType;
+
+                _tableFocus('DatabaseFieldName' + tbl.focusId, index);
+            }
+            else if (ui === 'table-indexes') {
+                tbl.curIndexName = val.name;
+                tbl.curIndexType = val.indexType;
+                tbl.curIndexFields = val.fields;
+
+                _tableFocus(tbl.focusId, index);
+            }
+        }
+
+        function _tableNewItem(tbl) {
+            _tableState(tbl, -1);
+
+            const ui = _tableUI(tbl);
+
+            if (ui === 'table-pair') {
+                tbl.newKey = null;
+                tbl.newValue = null;
+
+                _tableFocus('Key' + tbl.focusId, -1);
+            }
+            else if (ui === 'table-db-fields') {
+                tbl.newDatabaseFieldName = null;
+                tbl.newDatabaseFieldType = null;
+                tbl.newJavaFieldName = null;
+                tbl.newJavaFieldType = null;
+
+                _tableFocus('DatabaseFieldName' + tbl.focusId, -1);
+            }
+            else if (ui === 'table-indexes') {
+                tbl.newIndexName = null;
+                tbl.newIndexType = 'SORTED';
+                tbl.newIndexFields = null;
+
+                _tableFocus(tbl.focusId, -1);
+            }
+        }
+
+        return {
+            tableState: _tableState,
+            tableReset: _tableReset,
+            tableSaveAndReset: _tableSaveAndReset,
+            tableNewItem: _tableNewItem,
+            tableNewItemActive(tbl) {
+                return table.name === tbl.model && table.editIndex < 0;
+            },
+            tableEditing(tbl, index) {
+                return table.name === tbl.model && table.editIndex === index;
+            },
+            tableEditedRowIndex() {
+                return table.editIndex;
+            },
+            tableField() {
+                return table.field;
+            },
+            tableStartEdit: _tableStartEdit,
+            tableRemove(item, field, index) {
+                _tableReset();
+
+                _.get(_model(item, field), field.model).splice(index, 1);
+            },
+            tablePairValue: _tablePairValue,
+            tablePairSave(pairValid, item, field, index, stopEdit) {
+                const valid = pairValid(item, field, index, stopEdit);
+
+                if (valid) {
+                    const pairValue = _tablePairValue(field, index);
+
+                    let pairModel = {};
+
+                    const container = _.get(item, field.model);
+
+                    if (index < 0) {
+                        pairModel[field.keyName] = pairValue.key;
+                        pairModel[field.valueName] = pairValue.value;
+
+                        if (container)
+                            container.push(pairModel);
+                        else
+                            _.set(item, field.model, [pairModel]);
+
+                        if (!stopEdit)
+                            _tableNewItem(field);
+                    }
+                    else {
+                        pairModel = container[index];
+
+                        pairModel[field.keyName] = pairValue.key;
+                        pairModel[field.valueName] = pairValue.value;
+
+                        if (!stopEdit) {
+                            if (index < container.length - 1)
+                                _tableStartEdit(item, field, index + 1);
+                            else
+                                _tableNewItem(field);
+                        }
+                    }
+                }
+
+                return valid;
+            },
+            tablePairSaveVisible(field, index) {
+                const pairValue = _tablePairValue(field, index);
+
+                return !LegacyUtils.isEmptyString(pairValue.key) && !LegacyUtils.isEmptyString(pairValue.value);
+            },
+            tableFocusInvalidField(index, id) {
+                _tableFocus(id, index);
+
+                return false;
+            },
+            tableFieldId(index, id) {
+                return (index < 0 ? 'new' : 'cur') + id + (index >= 0 ? index : '');
+            }
+        };
+    }]];

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/frontend/app/services/LegacyUtils.service.js
----------------------------------------------------------------------
diff --git a/modules/web-console/frontend/app/services/LegacyUtils.service.js b/modules/web-console/frontend/app/services/LegacyUtils.service.js
new file mode 100644
index 0000000..ed555a1
--- /dev/null
+++ b/modules/web-console/frontend/app/services/LegacyUtils.service.js
@@ -0,0 +1,572 @@
+/*
+ * 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.
+ */
+
+// TODO: Refactor this service for legacy tables with more than one input field.
+export default ['IgniteLegacyUtils', ['IgniteErrorPopover', (ErrorPopover) => {
+    function isDefined(v) {
+        return !_.isNil(v);
+    }
+
+    function isEmptyString(s) {
+        if (isDefined(s))
+            return s.trim().length === 0;
+
+        return true;
+    }
+
+    const javaBuiltInClasses = [
+        'BigDecimal',
+        'Boolean',
+        'Byte',
+        'Date',
+        'Double',
+        'Float',
+        'Integer',
+        'Long',
+        'Object',
+        'Short',
+        'String',
+        'Time',
+        'Timestamp',
+        'UUID'
+    ];
+
+    const javaBuiltInTypes = [
+        'BigDecimal',
+        'boolean',
+        'Boolean',
+        'byte',
+        'Byte',
+        'Date',
+        'double',
+        'Double',
+        'float',
+        'Float',
+        'int',
+        'Integer',
+        'long',
+        'Long',
+        'Object',
+        'short',
+        'Short',
+        'String',
+        'Time',
+        'Timestamp',
+        'UUID'
+    ];
+
+    const javaBuiltInFullNameClasses = [
+        'java.math.BigDecimal',
+        'java.lang.Boolean',
+        'java.lang.Byte',
+        'java.sql.Date',
+        'java.lang.Double',
+        'java.lang.Float',
+        'java.lang.Integer',
+        'java.lang.Long',
+        'java.lang.Object',
+        'java.lang.Short',
+        'java.lang.String',
+        'java.sql.Time',
+        'java.sql.Timestamp',
+        'java.util.UUID'
+    ];
+
+    /**
+     * @param clsName Class name to check.
+     * @returns {Boolean} 'true' if given class name is a java build-in type.
+     */
+    function isJavaBuiltInClass(clsName) {
+        if (isEmptyString(clsName))
+            return false;
+
+        return _.includes(javaBuiltInClasses, clsName) || _.includes(javaBuiltInFullNameClasses, clsName);
+    }
+
+    const SUPPORTED_JDBC_TYPES = [
+        'BIGINT',
+        'BIT',
+        'BOOLEAN',
+        'BLOB',
+        'CHAR',
+        'CLOB',
+        'DATE',
+        'DECIMAL',
+        'DOUBLE',
+        'FLOAT',
+        'INTEGER',
+        'LONGNVARCHAR',
+        'LONGVARCHAR',
+        'NCHAR',
+        'NUMERIC',
+        'NVARCHAR',
+        'REAL',
+        'SMALLINT',
+        'TIME',
+        'TIMESTAMP',
+        'TINYINT',
+        'VARCHAR'
+    ];
+
+    const ALL_JDBC_TYPES = [
+        {dbName: 'BIT', dbType: -7, javaType: 'Boolean', primitiveType: 'boolean'},
+        {dbName: 'TINYINT', dbType: -6, javaType: 'Byte', primitiveType: 'byte'},
+        {dbName: 'SMALLINT', dbType: 5, javaType: 'Short', primitiveType: 'short'},
+        {dbName: 'INTEGER', dbType: 4, javaType: 'Integer', primitiveType: 'int'},
+        {dbName: 'BIGINT', dbType: -5, javaType: 'Long', primitiveType: 'long'},
+        {dbName: 'FLOAT', dbType: 6, javaType: 'Float', primitiveType: 'float'},
+        {dbName: 'REAL', dbType: 7, javaType: 'Double', primitiveType: 'double'},
+        {dbName: 'DOUBLE', dbType: 8, javaType: 'Double', primitiveType: 'double'},
+        {dbName: 'NUMERIC', dbType: 2, javaType: 'BigDecimal'},
+        {dbName: 'DECIMAL', dbType: 3, javaType: 'BigDecimal'},
+        {dbName: 'CHAR', dbType: 1, javaType: 'String'},
+        {dbName: 'VARCHAR', dbType: 12, javaType: 'String'},
+        {dbName: 'LONGVARCHAR', dbType: -1, javaType: 'String'},
+        {dbName: 'DATE', dbType: 91, javaType: 'Date'},
+        {dbName: 'TIME', dbType: 92, javaType: 'Time'},
+        {dbName: 'TIMESTAMP', dbType: 93, javaType: 'Timestamp'},
+        {dbName: 'BINARY', dbType: -2, javaType: 'Object'},
+        {dbName: 'VARBINARY', dbType: -3, javaType: 'Object'},
+        {dbName: 'LONGVARBINARY', dbType: -4, javaType: 'Object'},
+        {dbName: 'NULL', dbType: 0, javaType: 'Object'},
+        {dbName: 'OTHER', dbType: 1111, javaType: 'Object'},
+        {dbName: 'JAVA_OBJECT', dbType: 2000, javaType: 'Object'},
+        {dbName: 'DISTINCT', dbType: 2001, javaType: 'Object'},
+        {dbName: 'STRUCT', dbType: 2002, javaType: 'Object'},
+        {dbName: 'ARRAY', dbType: 2003, javaType: 'Object'},
+        {dbName: 'BLOB', dbType: 2004, javaType: 'Object'},
+        {dbName: 'CLOB', dbType: 2005, javaType: 'String'},
+        {dbName: 'REF', dbType: 2006, javaType: 'Object'},
+        {dbName: 'DATALINK', dbType: 70, javaType: 'Object'},
+        {dbName: 'BOOLEAN', dbType: 16, javaType: 'Boolean', primitiveType: 'boolean'},
+        {dbName: 'ROWID', dbType: -8, javaType: 'Object'},
+        {dbName: 'NCHAR', dbType: -15, javaType: 'String'},
+        {dbName: 'NVARCHAR', dbType: -9, javaType: 'String'},
+        {dbName: 'LONGNVARCHAR', dbType: -16, javaType: 'String'},
+        {dbName: 'NCLOB', dbType: 2011, javaType: 'String'},
+        {dbName: 'SQLXML', dbType: 2009, javaType: 'Object'}
+    ];
+
+    /*eslint-disable */
+    const JAVA_KEYWORDS = [
+        'abstract',
+        'assert',
+        'boolean',
+        'break',
+        'byte',
+        'case',
+        'catch',
+        'char',
+        'class',
+        'const',
+        'continue',
+        'default',
+        'do',
+        'double',
+        'else',
+        'enum',
+        'extends',
+        'false',
+        'final',
+        'finally',
+        'float',
+        'for',
+        'goto',
+        'if',
+        'implements',
+        'import',
+        'instanceof',
+        'int',
+        'interface',
+        'long',
+        'native',
+        'new',
+        'null',
+        'package',
+        'private',
+        'protected',
+        'public',
+        'return',
+        'short',
+        'static',
+        'strictfp',
+        'super',
+        'switch',
+        'synchronized',
+        'this',
+        'throw',
+        'throws',
+        'transient',
+        'true',
+        'try',
+        'void',
+        'volatile',
+        'while'
+    ];
+    /*eslint-enable */
+
+    const VALID_JAVA_IDENTIFIER = new RegExp('^[a-zA-Z_$][a-zA-Z\\d_$]*$');
+
+    function isValidJavaIdentifier(msg, ident, elemId, panels, panelId) {
+        if (isEmptyString(ident))
+            return ErrorPopover.show(elemId, msg + ' is invalid!', panels, panelId);
+
+        if (_.includes(JAVA_KEYWORDS, ident))
+            return ErrorPopover.show(elemId, msg + ' could not contains reserved java keyword: "' + ident + '"!', panels, panelId);
+
+        if (!VALID_JAVA_IDENTIFIER.test(ident))
+            return ErrorPopover.show(elemId, msg + ' contains invalid identifier: "' + ident + '"!', panels, panelId);
+
+        return true;
+    }
+
+    function getModel(obj, field) {
+        let path = field.path;
+
+        if (!isDefined(path) || !isDefined(obj))
+            return obj;
+
+        path = path.replace(/\[(\w+)\]/g, '.$1'); // convert indexes to properties
+        path = path.replace(/^\./, '');           // strip a leading dot
+
+        const segs = path.split('.');
+        let root = obj;
+
+        while (segs.length > 0) {
+            const pathStep = segs.shift();
+
+            if (typeof root[pathStep] === 'undefined')
+                root[pathStep] = {};
+
+            root = root[pathStep];
+        }
+
+        return root;
+    }
+
+    /**
+     * Extract datasource from cache or cluster.
+     *
+     * @param object Cache or cluster to extract datasource.
+     * @returns {*} Datasource object or null if not set.
+     */
+    function extractDataSource(object) {
+        // Extract from cluster object
+        if (_.get(object, 'discovery.kind') === 'Jdbc') {
+            const datasource = object.discovery.Jdbc;
+
+            if (datasource.dataSourceBean && datasource.dialect)
+                return datasource;
+        } // Extract from cache object
+        else if (_.get(object, 'cacheStoreFactory.kind')) {
+            const storeFactory = object.cacheStoreFactory[object.cacheStoreFactory.kind];
+
+            if (storeFactory.dialect || (storeFactory.connectVia === 'DataSource'))
+                return storeFactory;
+        }
+
+        return null;
+    }
+
+    const cacheStoreJdbcDialects = [
+        {value: 'Generic', label: 'Generic JDBC'},
+        {value: 'Oracle', label: 'Oracle'},
+        {value: 'DB2', label: 'IBM DB2'},
+        {value: 'SQLServer', label: 'Microsoft SQL Server'},
+        {value: 'MySQL', label: 'MySQL'},
+        {value: 'PostgreSQL', label: 'PostgreSQL'},
+        {value: 'H2', label: 'H2 database'}
+    ];
+
+    function domainForStoreConfigured(domain) {
+        const isEmpty = !isDefined(domain) || (isEmptyString(domain.databaseSchema) &&
+            isEmptyString(domain.databaseTable) &&
+            _.isEmpty(domain.keyFields) &&
+            _.isEmpty(domain.valueFields));
+
+        return !isEmpty;
+    }
+
+    const DS_CHECK_SUCCESS = {checked: true};
+
+    /**
+     * Compare datasources of caches or clusters.
+     *
+     * @param firstObj First cache or cluster.
+     * @param secondObj Second cache or cluster.
+     * @returns {*} Check result object.
+     */
+    function compareDataSources(firstObj, secondObj) {
+        const firstDs = extractDataSource(firstObj);
+        const secondDs = extractDataSource(secondObj);
+
+        if (firstDs && secondDs) {
+            const firstDB = firstDs.dialect;
+            const secondDB = secondDs.dialect;
+
+            if (firstDs.dataSourceBean === secondDs.dataSourceBean && firstDB !== secondDB)
+                return {checked: false, firstObj, firstDB, secondObj, secondDB};
+        }
+
+        return DS_CHECK_SUCCESS;
+    }
+
+    function compareSQLSchemaNames(firstCache, secondCache) {
+        const firstName = firstCache.sqlSchema;
+        const secondName = secondCache.sqlSchema;
+
+        if (firstName && secondName && (firstName === secondName))
+            return {checked: false, firstCache, secondCache};
+
+        return DS_CHECK_SUCCESS;
+    }
+
+    function toJavaName(prefix, name) {
+        const javaName = name ? name.replace(/[^A-Za-z_0-9]+/g, '_') : 'dflt';
+
+        return prefix + javaName.charAt(0).toLocaleUpperCase() + javaName.slice(1);
+    }
+
+    return {
+        getModel,
+        mkOptions(options) {
+            return _.map(options, (option) => {
+                return {value: option, label: isDefined(option) ? option : 'Not set'};
+            });
+        },
+        isDefined,
+        hasProperty(obj, props) {
+            for (const propName in props) {
+                if (props.hasOwnProperty(propName)) {
+                    if (obj[propName])
+                        return true;
+                }
+            }
+
+            return false;
+        },
+        isEmptyString,
+        SUPPORTED_JDBC_TYPES,
+        findJdbcType(jdbcType) {
+            const res = _.find(ALL_JDBC_TYPES, (item) => item.dbType === jdbcType);
+
+            return res ? res : {dbName: 'Unknown', javaType: 'Unknown'};
+        },
+        javaBuiltInClasses,
+        javaBuiltInTypes,
+        isJavaBuiltInClass,
+        isValidJavaIdentifier,
+        isValidJavaClass(msg, ident, allowBuiltInClass, elemId, packageOnly, panels, panelId) {
+            if (isEmptyString(ident))
+                return ErrorPopover.show(elemId, msg + ' could not be empty!', panels, panelId);
+
+            const parts = ident.split('.');
+
+            const len = parts.length;
+
+            if (!allowBuiltInClass && isJavaBuiltInClass(ident))
+                return ErrorPopover.show(elemId, msg + ' should not be the Java build-in class!', panels, panelId);
+
+            if (len < 2 && !isJavaBuiltInClass(ident) && !packageOnly)
+                return ErrorPopover.show(elemId, msg + ' does not have package specified!', panels, panelId);
+
+            for (let i = 0; i < parts.length; i++) {
+                const part = parts[i];
+
+                if (!isValidJavaIdentifier(msg, part, elemId, panels, panelId))
+                    return false;
+            }
+
+            return true;
+        },
+        domainForQueryConfigured(domain) {
+            const isEmpty = !isDefined(domain) || (_.isEmpty(domain.fields) &&
+                _.isEmpty(domain.aliases) &&
+                _.isEmpty(domain.indexes));
+
+            return !isEmpty;
+        },
+        domainForStoreConfigured,
+        download(type, name, data) {
+            const file = document.createElement('a');
+
+            file.setAttribute('href', 'data:' + type + ';charset=utf-8,' + data);
+            file.setAttribute('download', name);
+            file.setAttribute('target', '_self');
+
+            file.style.display = 'none';
+
+            document.body.appendChild(file);
+
+            file.click();
+
+            document.body.removeChild(file);
+        },
+        getQueryVariable(name) {
+            const attrs = window.location.search.substring(1).split('&');
+            const attr = _.find(attrs, (a) => a === name || (a.indexOf('=') >= 0 && a.substr(0, a.indexOf('=')) === name));
+
+            if (!isDefined(attr))
+                return null;
+
+            if (attr === name)
+                return true;
+
+            return attr.substr(attr.indexOf('=') + 1);
+        },
+        cacheStoreJdbcDialects,
+        cacheStoreJdbcDialectsLabel(dialect) {
+            const found = _.find(cacheStoreJdbcDialects, (dialectVal) => dialectVal.value === dialect);
+
+            return found ? found.label : null;
+        },
+        checkDataSources(cluster, caches, checkCacheExt) {
+            let res = DS_CHECK_SUCCESS;
+
+            _.find(caches, (curCache, curIx) => {
+                res = compareDataSources(curCache, cluster);
+
+                if (!res.checked)
+                    return true;
+
+                if (isDefined(checkCacheExt)) {
+                    if (checkCacheExt._id !== curCache._id) {
+                        res = compareDataSources(checkCacheExt, curCache);
+
+                        return !res.checked;
+                    }
+
+                    return false;
+                }
+
+                return _.find(caches, (checkCache, checkIx) => {
+                    if (checkIx < curIx) {
+                        res = compareDataSources(checkCache, curCache);
+
+                        return !res.checked;
+                    }
+
+                    return false;
+                });
+            });
+
+            return res;
+        },
+        checkCacheSQLSchemas(caches, checkCacheExt) {
+            let res = DS_CHECK_SUCCESS;
+
+            _.find(caches, (curCache, curIx) => {
+                if (isDefined(checkCacheExt)) {
+                    if (checkCacheExt._id !== curCache._id) {
+                        res = compareSQLSchemaNames(checkCacheExt, curCache);
+
+                        return !res.checked;
+                    }
+
+                    return false;
+                }
+
+                return _.find(caches, (checkCache, checkIx) => {
+                    if (checkIx < curIx) {
+                        res = compareSQLSchemaNames(checkCache, curCache);
+
+                        return !res.checked;
+                    }
+
+                    return false;
+                });
+            });
+
+            return res;
+        },
+        autoCacheStoreConfiguration(cache, domains) {
+            const cacheStoreFactory = isDefined(cache.cacheStoreFactory) &&
+                isDefined(cache.cacheStoreFactory.kind);
+
+            if (!cacheStoreFactory && _.findIndex(domains, domainForStoreConfigured) >= 0) {
+                const dflt = !cache.readThrough && !cache.writeThrough;
+
+                return {
+                    cacheStoreFactory: {
+                        kind: 'CacheJdbcPojoStoreFactory',
+                        CacheJdbcPojoStoreFactory: {
+                            dataSourceBean: toJavaName('ds', cache.name),
+                            dialect: 'Generic'
+                        },
+                        CacheJdbcBlobStoreFactory: {connectVia: 'DataSource'}
+                    },
+                    readThrough: dflt || cache.readThrough,
+                    writeThrough: dflt || cache.writeThrough
+                };
+            }
+        },
+        autoClusterSwapSpiConfiguration(cluster, caches) {
+            const swapConfigured = cluster.swapSpaceSpi && cluster.swapSpaceSpi.kind;
+
+            if (!swapConfigured && _.find(caches, (cache) => cache.swapEnabled))
+                return {swapSpaceSpi: {kind: 'FileSwapSpaceSpi'}};
+
+            return null;
+        },
+        randomString(len) {
+            const possible = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';
+            const possibleLen = possible.length;
+
+            let res = '';
+
+            for (let i = 0; i < len; i++)
+                res += possible.charAt(Math.floor(Math.random() * possibleLen));
+
+            return res;
+        },
+        checkFieldValidators(ui) {
+            const form = ui.inputForm;
+            const errors = form.$error;
+            const errKeys = Object.keys(errors);
+
+            if (errKeys && errKeys.length > 0) {
+                const firstErrorKey = errKeys[0];
+
+                const firstError = errors[firstErrorKey][0];
+                const actualError = firstError.$error[firstErrorKey][0];
+
+                const errNameFull = actualError.$name;
+                const errNameShort = errNameFull.endsWith('TextInput') ? errNameFull.substring(0, errNameFull.length - 9) : errNameFull;
+
+                const extractErrorMessage = (errName) => {
+                    try {
+                        return errors[firstErrorKey][0].$errorMessages[errName][firstErrorKey];
+                    }
+                    catch (ignored) {
+                        try {
+                            return form[firstError.$name].$errorMessages[errName][firstErrorKey];
+                        }
+                        catch (ignited) {
+                            return false;
+                        }
+                    }
+                };
+
+                const msg = extractErrorMessage(errNameFull) || extractErrorMessage(errNameShort) || 'Invalid value!';
+
+                return ErrorPopover.show(errNameFull, msg, ui, firstError.$name);
+            }
+
+            return true;
+        }
+    };
+}]];

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/frontend/app/services/Messages.service.js
----------------------------------------------------------------------
diff --git a/modules/web-console/frontend/app/services/Messages.service.js b/modules/web-console/frontend/app/services/Messages.service.js
new file mode 100644
index 0000000..e679488
--- /dev/null
+++ b/modules/web-console/frontend/app/services/Messages.service.js
@@ -0,0 +1,63 @@
+/*
+ * 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.
+ */
+
+// Service to show various information and error messages.
+export default ['IgniteMessages', ['$alert', ($alert) => {
+    // Common instance of alert modal.
+    let msgModal;
+
+    const errorMessage = (prefix, err) => {
+        prefix = prefix || '';
+
+        if (err) {
+            if (err.hasOwnProperty('message'))
+                return prefix + err.message;
+
+            return prefix + err;
+        }
+
+        return prefix + 'Internal error.';
+    };
+
+    const hideAlert = () => {
+        if (msgModal)
+            msgModal.hide();
+    };
+
+    const _showMessage = (err, type, duration, icon) => {
+        hideAlert();
+
+        const title = errorMessage(null, err);
+
+        msgModal = $alert({type, title, duration});
+
+        msgModal.$scope.icon = icon;
+    };
+
+    return {
+        errorMessage,
+        hideAlert,
+        showError(err) {
+            _showMessage(err, 'danger', 10, 'fa-exclamation-triangle');
+
+            return false;
+        },
+        showInfo(err) {
+            _showMessage(err, 'success', 3, 'fa-check-circle-o');
+        }
+    };
+}]];

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/frontend/app/services/ModelNormalizer.service.js
----------------------------------------------------------------------
diff --git a/modules/web-console/frontend/app/services/ModelNormalizer.service.js b/modules/web-console/frontend/app/services/ModelNormalizer.service.js
new file mode 100644
index 0000000..4c7052b
--- /dev/null
+++ b/modules/web-console/frontend/app/services/ModelNormalizer.service.js
@@ -0,0 +1,59 @@
+/*
+ * 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.
+ */
+
+// Service to normalize objects for dirty checks.
+export default ['IgniteModelNormalizer', () => {
+    /**
+     * Normalize object for dirty checks.
+     *
+     * @param original
+     * @param dest
+     * @returns {*}
+     */
+    const normalize = (original, dest) => {
+        if (_.isUndefined(original))
+            return dest;
+
+        if (_.isObject(original)) {
+            _.forOwn(original, (value, key) => {
+                if (/\$\$hashKey/.test(key))
+                    return;
+
+                const attr = normalize(value);
+
+                if (!_.isNil(attr)) {
+                    dest = dest || {};
+                    dest[key] = attr;
+                }
+            });
+        } else if (_.isBoolean(original) && original === true)
+            dest = original;
+        else if ((_.isString(original) && original.length) || _.isNumber(original))
+            dest = original;
+        else if (_.isArray(original) && original.length)
+            dest = _.map(original, (value) => normalize(value, {}));
+
+        return dest;
+    };
+
+    return {
+        normalize,
+        isEqual(prev, cur) {
+            return _.isEqual(prev, normalize(cur));
+        }
+    };
+}];

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/frontend/app/services/UnsavedChangesGuard.service.js
----------------------------------------------------------------------
diff --git a/modules/web-console/frontend/app/services/UnsavedChangesGuard.service.js b/modules/web-console/frontend/app/services/UnsavedChangesGuard.service.js
new file mode 100644
index 0000000..91244b0
--- /dev/null
+++ b/modules/web-console/frontend/app/services/UnsavedChangesGuard.service.js
@@ -0,0 +1,38 @@
+/*
+ * 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 MSG = 'You have unsaved changes.\n\nAre you sure you want to discard them?';
+
+// Service that show confirmation about unsaved changes on user change location.
+export default ['IgniteUnsavedChangesGuard', ['$rootScope', ($root) => {
+    return {
+        install(scope, customDirtyCheck = () => scope.ui.inputForm.$dirty) {
+            scope.$on('$destroy', () => window.onbeforeunload = null);
+
+            const unbind = $root.$on('$stateChangeStart', (event) => {
+                if (_.get(scope, 'ui.inputForm', false) && customDirtyCheck()) {
+                    if (!confirm(MSG)) // eslint-disable-line no-alert
+                        event.preventDefault();
+                    else
+                        unbind();
+                }
+            });
+
+            window.onbeforeunload = () => _.get(scope, 'ui.inputForm.$dirty', false) ? MSG : null;
+        }
+    };
+}]];

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/frontend/app/vendor.js
----------------------------------------------------------------------
diff --git a/modules/web-console/frontend/app/vendor.js b/modules/web-console/frontend/app/vendor.js
new file mode 100644
index 0000000..0322887
--- /dev/null
+++ b/modules/web-console/frontend/app/vendor.js
@@ -0,0 +1,55 @@
+/*
+ * 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 'jquery';
+import 'angular';
+import 'angular-acl';
+import 'angular-animate';
+import 'angular-sanitize';
+import 'angular-strap';
+import 'angular-strap/dist/angular-strap.tpl';
+import 'angular-socket-io';
+import 'angular-retina';
+import 'angular-ui-router';
+import 'ui-router-metatags/dist/ui-router-metatags';
+import 'angular-smart-table';
+import 'angular-ui-grid/ui-grid';
+import 'angular-drag-and-drop-lists';
+import 'angular-nvd3';
+import 'angular-tree-control';
+import 'angular-gridster';
+import 'bootstrap-sass/assets/javascripts/bootstrap/transition';
+import 'bootstrap-sass/assets/javascripts/bootstrap/carousel';
+import 'brace';
+import 'brace/mode/xml';
+import 'brace/mode/sql';
+import 'brace/mode/java';
+import 'brace/mode/dockerfile';
+import 'brace/mode/snippets';
+import 'brace/theme/chrome';
+import 'brace/ext/language_tools';
+import 'brace/ext/searchbox';
+import 'file-saver';
+import 'jszip';
+import 'nvd3';
+import 'query-command-supported';
+import 'angular-gridster/dist/angular-gridster.min.css';
+import 'angular-tree-control/css/tree-control-attribute.css';
+import 'angular-tree-control/css/tree-control.css';
+import 'angular-ui-grid/ui-grid.css';
+import 'angular-motion/dist/angular-motion.css';
+import 'nvd3/build/nv.d3.css';

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/frontend/controllers/admin-controller.js
----------------------------------------------------------------------
diff --git a/modules/web-console/frontend/controllers/admin-controller.js b/modules/web-console/frontend/controllers/admin-controller.js
new file mode 100644
index 0000000..57a39b2
--- /dev/null
+++ b/modules/web-console/frontend/controllers/admin-controller.js
@@ -0,0 +1,92 @@
+/*
+ * 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.
+ */
+
+// Controller for Admin screen.
+export default ['adminController', [
+    '$rootScope', '$scope', '$http', '$q', '$state', 'IgniteMessages', 'IgniteConfirm', 'User', 'IgniteCountries',
+    ($rootScope, $scope, $http, $q, $state, Messages, Confirm, User, Countries) => {
+        $scope.users = null;
+
+        const _reloadUsers = () => {
+            $http.post('/api/v1/admin/list')
+                .success((users) => {
+                    $scope.users = users;
+
+                    _.forEach($scope.users, (user) => {
+                        user.userName = user.firstName + ' ' + user.lastName;
+                        user.countryCode = Countries.getByName(user.country).code;
+                        user.label = user.userName + ' ' + user.email + ' ' +
+                            (user.company || '') + ' ' + (user.countryCode || '');
+                    });
+                })
+                .error(Messages.showError);
+        };
+
+        _reloadUsers();
+
+        $scope.becomeUser = function(user) {
+            $http.get('/api/v1/admin/become', { params: {viewedUserId: user._id}})
+                .catch(({data}) => Promise.reject(data))
+                .then(User.load)
+                .then((becomeUser) => {
+                    $rootScope.$broadcast('user', becomeUser);
+
+                    $state.go('base.configuration.clusters');
+                })
+                .catch(Messages.showError);
+        };
+
+        $scope.removeUser = (user) => {
+            Confirm.confirm('Are you sure you want to remove user: "' + user.userName + '"?')
+                .then(() => {
+                    $http.post('/api/v1/admin/remove', {userId: user._id})
+                        .success(() => {
+                            const i = _.findIndex($scope.users, (u) => u._id === user._id);
+
+                            if (i >= 0)
+                                $scope.users.splice(i, 1);
+
+                            Messages.showInfo('User has been removed: "' + user.userName + '"');
+                        })
+                        .error((err, status) => {
+                            if (status === 503)
+                                Messages.showInfo(err);
+                            else
+                                Messages.showError(Messages.errorMessage('Failed to remove user: ', err));
+                        });
+                });
+        };
+
+        $scope.toggleAdmin = (user) => {
+            if (user.adminChanging)
+                return;
+
+            user.adminChanging = true;
+
+            $http.post('/api/v1/admin/save', {userId: user._id, adminFlag: !user.admin})
+                .success(() => {
+                    user.admin = !user.admin;
+
+                    Messages.showInfo('Admin right was successfully toggled for user: "' + user.userName + '"');
+                })
+                .error((err) => {
+                    Messages.showError(Messages.errorMessage('Failed to toggle admin right for user: ', err));
+                })
+                .finally(() => user.adminChanging = false);
+        };
+    }
+]];

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/frontend/controllers/caches-controller.js
----------------------------------------------------------------------
diff --git a/modules/web-console/frontend/controllers/caches-controller.js b/modules/web-console/frontend/controllers/caches-controller.js
new file mode 100644
index 0000000..9873051
--- /dev/null
+++ b/modules/web-console/frontend/controllers/caches-controller.js
@@ -0,0 +1,524 @@
+/*
+ * 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.
+ */
+
+// Controller for Caches screen.
+export default ['cachesController', [
+    '$scope', '$http', '$state', '$filter', '$timeout', 'IgniteLegacyUtils', 'IgniteMessages', 'IgniteConfirm', 'IgniteClone', 'IgniteLoading', 'IgniteModelNormalizer', 'IgniteUnsavedChangesGuard', 'igniteConfigurationResource', 'IgniteErrorPopover', 'IgniteFormUtils',
+    function($scope, $http, $state, $filter, $timeout, LegacyUtils, Messages, Confirm, Clone, Loading, ModelNormalizer, UnsavedChangesGuard, Resource, ErrorPopover, FormUtils) {
+        UnsavedChangesGuard.install($scope);
+
+        const emptyCache = {empty: true};
+
+        let __original_value;
+
+        const blank = {
+            evictionPolicy: {},
+            cacheStoreFactory: {
+                CacheHibernateBlobStoreFactory: {
+                    hibernateProperties: []
+                }
+            },
+            nearConfiguration: {},
+            sqlFunctionClasses: []
+        };
+
+        // We need to initialize backupItem with empty object in order to properly used from angular directives.
+        $scope.backupItem = emptyCache;
+
+        $scope.ui = FormUtils.formUI();
+        $scope.ui.activePanels = [0];
+        $scope.ui.topPanels = [0, 1, 2, 3];
+
+        $scope.saveBtnTipText = FormUtils.saveBtnTipText;
+        $scope.widthIsSufficient = FormUtils.widthIsSufficient;
+        $scope.offHeapMode = 'DISABLED';
+
+        $scope.contentVisible = function() {
+            const item = $scope.backupItem;
+
+            return !item.empty && (!item._id || _.find($scope.displayedRows, {_id: item._id}));
+        };
+
+        $scope.toggleExpanded = function() {
+            $scope.ui.expanded = !$scope.ui.expanded;
+
+            ErrorPopover.hide();
+        };
+
+        $scope.caches = [];
+        $scope.domains = [];
+
+        function _cacheLbl(cache) {
+            return cache.name + ', ' + cache.cacheMode + ', ' + cache.atomicityMode;
+        }
+
+        function selectFirstItem() {
+            if ($scope.caches.length > 0)
+                $scope.selectItem($scope.caches[0]);
+        }
+
+        function cacheDomains(item) {
+            return _.reduce($scope.domains, function(memo, domain) {
+                if (item && _.includes(item.domains, domain.value))
+                    memo.push(domain.meta);
+
+                return memo;
+            }, []);
+        }
+
+        const setOffHeapMode = (item) => {
+            if (_.isNil(item.offHeapMaxMemory))
+                return;
+
+            return item.offHeapMode = Math.sign(item.offHeapMaxMemory);
+        };
+
+        const setOffHeapMaxMemory = (value) => {
+            const item = $scope.backupItem;
+
+            if (_.isNil(value) || value <= 0)
+                return item.offHeapMaxMemory = value;
+
+            item.offHeapMaxMemory = item.offHeapMaxMemory > 0 ? item.offHeapMaxMemory : null;
+        };
+
+        Loading.start('loadingCachesScreen');
+
+        // When landing on the page, get caches and show them.
+        Resource.read()
+            .then(({spaces, clusters, caches, domains, igfss}) => {
+                const validFilter = $filter('domainsValidation');
+
+                $scope.spaces = spaces;
+                $scope.caches = caches;
+                $scope.igfss = _.map(igfss, (igfs) => ({
+                    label: igfs.name,
+                    value: igfs._id,
+                    igfs
+                }));
+
+                _.forEach($scope.caches, (cache) => cache.label = _cacheLbl(cache));
+
+                $scope.clusters = _.map(clusters, (cluster) => ({
+                    value: cluster._id,
+                    label: cluster.name,
+                    discovery: cluster.discovery,
+                    caches: cluster.caches
+                }));
+
+                $scope.domains = _.sortBy(_.map(validFilter(domains, true, false), (domain) => ({
+                    label: domain.valueType,
+                    value: domain._id,
+                    kind: domain.kind,
+                    meta: domain
+                })), 'label');
+
+                if ($state.params.linkId)
+                    $scope.createItem($state.params.linkId);
+                else {
+                    const lastSelectedCache = angular.fromJson(sessionStorage.lastSelectedCache);
+
+                    if (lastSelectedCache) {
+                        const idx = _.findIndex($scope.caches, function(cache) {
+                            return cache._id === lastSelectedCache;
+                        });
+
+                        if (idx >= 0)
+                            $scope.selectItem($scope.caches[idx]);
+                        else {
+                            sessionStorage.removeItem('lastSelectedCache');
+
+                            selectFirstItem();
+                        }
+                    }
+                    else
+                        selectFirstItem();
+                }
+
+                $scope.$watch('ui.inputForm.$valid', function(valid) {
+                    if (valid && ModelNormalizer.isEqual(__original_value, $scope.backupItem))
+                        $scope.ui.inputForm.$dirty = false;
+                });
+
+                $scope.$watch('backupItem', function(val) {
+                    if (!$scope.ui.inputForm)
+                        return;
+
+                    const form = $scope.ui.inputForm;
+
+                    if (form.$valid && ModelNormalizer.isEqual(__original_value, val))
+                        form.$setPristine();
+                    else
+                        form.$setDirty();
+                }, true);
+
+                $scope.$watch('backupItem.offHeapMode', setOffHeapMaxMemory);
+
+                $scope.$watch('ui.activePanels.length', () => {
+                    ErrorPopover.hide();
+                });
+            })
+            .catch(Messages.showError)
+            .then(() => {
+                $scope.ui.ready = true;
+                $scope.ui.inputForm && $scope.ui.inputForm.$setPristine();
+
+                Loading.finish('loadingCachesScreen');
+            });
+
+        $scope.selectItem = function(item, backup) {
+            function selectItem() {
+                $scope.selectedItem = item;
+
+                if (item && !_.get(item.cacheStoreFactory.CacheJdbcBlobStoreFactory, 'connectVia'))
+                    _.set(item.cacheStoreFactory, 'CacheJdbcBlobStoreFactory.connectVia', 'DataSource');
+
+                try {
+                    if (item && item._id)
+                        sessionStorage.lastSelectedCache = angular.toJson(item._id);
+                    else
+                        sessionStorage.removeItem('lastSelectedCache');
+                }
+                catch (ignored) {
+                    // No-op.
+                }
+
+                if (backup)
+                    $scope.backupItem = backup;
+                else if (item)
+                    $scope.backupItem = angular.copy(item);
+                else
+                    $scope.backupItem = emptyCache;
+
+                $scope.backupItem = angular.merge({}, blank, $scope.backupItem);
+
+                if ($scope.ui.inputForm) {
+                    $scope.ui.inputForm.$error = {};
+                    $scope.ui.inputForm.$setPristine();
+                }
+
+                setOffHeapMode($scope.backupItem);
+
+                __original_value = ModelNormalizer.normalize($scope.backupItem);
+
+                if (LegacyUtils.getQueryVariable('new'))
+                    $state.go('base.configuration.caches');
+            }
+
+            FormUtils.confirmUnsavedChanges($scope.backupItem && $scope.ui.inputForm && $scope.ui.inputForm.$dirty, selectItem);
+        };
+
+        $scope.linkId = () => $scope.backupItem._id ? $scope.backupItem._id : 'create';
+
+        function prepareNewItem(linkId) {
+            return {
+                space: $scope.spaces[0]._id,
+                cacheMode: 'PARTITIONED',
+                atomicityMode: 'ATOMIC',
+                readFromBackup: true,
+                copyOnRead: true,
+                clusters: linkId && _.find($scope.clusters, {value: linkId})
+                    ? [linkId] : _.map($scope.clusters, function(cluster) { return cluster.value; }),
+                domains: linkId && _.find($scope.domains, { value: linkId }) ? [linkId] : [],
+                cacheStoreFactory: {CacheJdbcBlobStoreFactory: {connectVia: 'DataSource'}}
+            };
+        }
+
+        // Add new cache.
+        $scope.createItem = function(linkId) {
+            $timeout(() => FormUtils.ensureActivePanel($scope.ui, 'general', 'cacheNameInput'));
+
+            $scope.selectItem(null, prepareNewItem(linkId));
+        };
+
+        function cacheClusters() {
+            return _.filter($scope.clusters, (cluster) => _.includes($scope.backupItem.clusters, cluster.value));
+        }
+
+        function clusterCaches(cluster) {
+            const caches = _.filter($scope.caches,
+                (cache) => cache._id !== $scope.backupItem._id && _.includes(cluster.caches, cache._id));
+
+            caches.push($scope.backupItem);
+
+            return caches;
+        }
+
+        function checkDataSources() {
+            const clusters = cacheClusters();
+
+            let checkRes = {checked: true};
+
+            const failCluster = _.find(clusters, (cluster) => {
+                const caches = clusterCaches(cluster);
+
+                checkRes = LegacyUtils.checkDataSources(cluster, caches, $scope.backupItem);
+
+                return !checkRes.checked;
+            });
+
+            if (!checkRes.checked) {
+                if (_.get(checkRes.secondObj, 'discovery.kind') === 'Jdbc') {
+                    return ErrorPopover.show(checkRes.firstObj.cacheStoreFactory.kind === 'CacheJdbcPojoStoreFactory' ? 'pojoDialectInput' : 'blobDialectInput',
+                        'Found cluster "' + failCluster.label + '" with the same data source bean name "' +
+                        checkRes.secondObj.discovery.Jdbc.dataSourceBean + '" and different database: "' +
+                        LegacyUtils.cacheStoreJdbcDialectsLabel(checkRes.firstDB) + '" in current cache and "' +
+                        LegacyUtils.cacheStoreJdbcDialectsLabel(checkRes.secondDB) + '" in"' + checkRes.secondObj.label + '" cluster',
+                        $scope.ui, 'store', 10000);
+                }
+
+                return ErrorPopover.show(checkRes.firstObj.cacheStoreFactory.kind === 'CacheJdbcPojoStoreFactory' ? 'pojoDialectInput' : 'blobDialectInput',
+                    'Found cache "' + checkRes.secondObj.name + '" in cluster "' + failCluster.label + '" ' +
+                    'with the same data source bean name "' + checkRes.firstObj.cacheStoreFactory[checkRes.firstObj.cacheStoreFactory.kind].dataSourceBean +
+                    '" and different database: "' + LegacyUtils.cacheStoreJdbcDialectsLabel(checkRes.firstDB) + '" in current cache and "' +
+                    LegacyUtils.cacheStoreJdbcDialectsLabel(checkRes.secondDB) + '" in "' + checkRes.secondObj.name + '" cache',
+                    $scope.ui, 'store', 10000);
+            }
+
+            return true;
+        }
+
+        function checkSQLSchemas() {
+            const clusters = cacheClusters();
+
+            let checkRes = {checked: true};
+
+            const failCluster = _.find(clusters, (cluster) => {
+                const caches = clusterCaches(cluster);
+
+                checkRes = LegacyUtils.checkCacheSQLSchemas(caches, $scope.backupItem);
+
+                return !checkRes.checked;
+            });
+
+            if (!checkRes.checked) {
+                return ErrorPopover.show('sqlSchemaInput',
+                    'Found cache "' + checkRes.secondCache.name + '" in cluster "' + failCluster.label + '" ' +
+                    'with the same SQL schema name "' + checkRes.firstCache.sqlSchema + '"',
+                    $scope.ui, 'query', 10000);
+            }
+
+            return true;
+        }
+
+        function checkStoreFactoryBean(storeFactory, beanFieldId) {
+            if (!LegacyUtils.isValidJavaIdentifier('Data source bean', storeFactory.dataSourceBean, beanFieldId, $scope.ui, 'store'))
+                return false;
+
+            return checkDataSources();
+        }
+
+        function checkStoreFactory(item) {
+            const cacheStoreFactorySelected = item.cacheStoreFactory && item.cacheStoreFactory.kind;
+
+            if (cacheStoreFactorySelected) {
+                const storeFactory = item.cacheStoreFactory[item.cacheStoreFactory.kind];
+
+                if (item.cacheStoreFactory.kind === 'CacheJdbcPojoStoreFactory' && !checkStoreFactoryBean(storeFactory, 'pojoDataSourceBean'))
+                    return false;
+
+                if (item.cacheStoreFactory.kind === 'CacheJdbcBlobStoreFactory' && storeFactory.connectVia !== 'URL'
+                    && !checkStoreFactoryBean(storeFactory, 'blobDataSourceBean'))
+                    return false;
+            }
+
+            if ((item.readThrough || item.writeThrough) && !cacheStoreFactorySelected)
+                return ErrorPopover.show('cacheStoreFactoryInput', (item.readThrough ? 'Read' : 'Write') + ' through are enabled but store is not configured!', $scope.ui, 'store');
+
+            if (item.writeBehindEnabled && !cacheStoreFactorySelected)
+                return ErrorPopover.show('cacheStoreFactoryInput', 'Write behind enabled but store is not configured!', $scope.ui, 'store');
+
+            if (cacheStoreFactorySelected && !item.readThrough && !item.writeThrough)
+                return ErrorPopover.show('readThroughLabel', 'Store is configured but read/write through are not enabled!', $scope.ui, 'store');
+
+            return true;
+        }
+
+        // Check cache logical consistency.
+        function validate(item) {
+            ErrorPopover.hide();
+
+            if (LegacyUtils.isEmptyString(item.name))
+                return ErrorPopover.show('cacheNameInput', 'Cache name should not be empty!', $scope.ui, 'general');
+
+            if (item.memoryMode === 'ONHEAP_TIERED' && item.offHeapMaxMemory > 0 && !LegacyUtils.isDefined(item.evictionPolicy.kind))
+                return ErrorPopover.show('evictionPolicyKindInput', 'Eviction policy should be configured!', $scope.ui, 'memory');
+
+            if (!LegacyUtils.checkFieldValidators($scope.ui))
+                return false;
+
+            if (item.memoryMode === 'OFFHEAP_VALUES' && !_.isEmpty(item.domains))
+                return ErrorPopover.show('memoryModeInput', 'Query indexing could not be enabled while values are stored off-heap!', $scope.ui, 'memory');
+
+            if (item.memoryMode === 'OFFHEAP_TIERED' && item.offHeapMaxMemory === -1)
+                return ErrorPopover.show('offHeapModeInput', 'Invalid value!', $scope.ui, 'memory');
+
+            if (!checkSQLSchemas())
+                return false;
+
+            if (!checkStoreFactory(item))
+                return false;
+
+            if (item.writeBehindFlushSize === 0 && item.writeBehindFlushFrequency === 0)
+                return ErrorPopover.show('writeBehindFlushSizeInput', 'Both "Flush frequency" and "Flush size" are not allowed as 0!', $scope.ui, 'store');
+
+            if (item.nodeFilter && item.nodeFilter.kind === 'OnNodes' && _.isEmpty(item.nodeFilter.OnNodes.nodeIds))
+                return ErrorPopover.show('nodeFilter-title', 'At least one node ID should be specified!', $scope.ui, 'nodeFilter');
+
+            return true;
+        }
+
+        // Save cache in database.
+        function save(item) {
+            $http.post('/api/v1/configuration/caches/save', item)
+                .success(function(_id) {
+                    item.label = _cacheLbl(item);
+
+                    $scope.ui.inputForm.$setPristine();
+
+                    const idx = _.findIndex($scope.caches, function(cache) {
+                        return cache._id === _id;
+                    });
+
+                    if (idx >= 0)
+                        angular.merge($scope.caches[idx], item);
+                    else {
+                        item._id = _id;
+                        $scope.caches.push(item);
+                    }
+
+                    _.forEach($scope.clusters, (cluster) => {
+                        if (_.includes(item.clusters, cluster.value))
+                            cluster.caches = _.union(cluster.caches, [_id]);
+                        else
+                            _.remove(cluster.caches, (id) => id === _id);
+                    });
+
+                    _.forEach($scope.domains, (domain) => {
+                        if (_.includes(item.domains, domain.value))
+                            domain.meta.caches = _.union(domain.meta.caches, [_id]);
+                        else
+                            _.remove(domain.meta.caches, (id) => id === _id);
+                    });
+
+                    $scope.selectItem(item);
+
+                    Messages.showInfo('Cache "' + item.name + '" saved.');
+                })
+                .error(Messages.showError);
+        }
+
+        // Save cache.
+        $scope.saveItem = function() {
+            const item = $scope.backupItem;
+
+            angular.extend(item, LegacyUtils.autoCacheStoreConfiguration(item, cacheDomains(item)));
+
+            if (validate(item))
+                save(item);
+        };
+
+        function _cacheNames() {
+            return _.map($scope.caches, function(cache) {
+                return cache.name;
+            });
+        }
+
+        // Clone cache with new name.
+        $scope.cloneItem = function() {
+            if (validate($scope.backupItem)) {
+                Clone.confirm($scope.backupItem.name, _cacheNames()).then(function(newName) {
+                    const item = angular.copy($scope.backupItem);
+
+                    delete item._id;
+
+                    item.name = newName;
+
+                    delete item.sqlSchema;
+
+                    save(item);
+                });
+            }
+        };
+
+        // Remove cache from db.
+        $scope.removeItem = function() {
+            const selectedItem = $scope.selectedItem;
+
+            Confirm.confirm('Are you sure you want to remove cache: "' + selectedItem.name + '"?')
+                .then(function() {
+                    const _id = selectedItem._id;
+
+                    $http.post('/api/v1/configuration/caches/remove', {_id})
+                        .success(function() {
+                            Messages.showInfo('Cache has been removed: ' + selectedItem.name);
+
+                            const caches = $scope.caches;
+
+                            const idx = _.findIndex(caches, function(cache) {
+                                return cache._id === _id;
+                            });
+
+                            if (idx >= 0) {
+                                caches.splice(idx, 1);
+
+                                $scope.ui.inputForm.$setPristine();
+
+                                if (caches.length > 0)
+                                    $scope.selectItem(caches[0]);
+                                else
+                                    $scope.backupItem = emptyCache;
+
+                                _.forEach($scope.clusters, (cluster) => _.remove(cluster.caches, (id) => id === _id));
+                                _.forEach($scope.domains, (domain) => _.remove(domain.meta.caches, (id) => id === _id));
+                            }
+                        })
+                        .error(Messages.showError);
+                });
+        };
+
+        // Remove all caches from db.
+        $scope.removeAllItems = function() {
+            Confirm.confirm('Are you sure you want to remove all caches?')
+                .then(function() {
+                    $http.post('/api/v1/configuration/caches/remove/all')
+                        .success(function() {
+                            Messages.showInfo('All caches have been removed');
+
+                            $scope.caches = [];
+
+                            _.forEach($scope.clusters, (cluster) => cluster.caches = []);
+                            _.forEach($scope.domains, (domain) => domain.meta.caches = []);
+
+                            $scope.backupItem = emptyCache;
+                            $scope.ui.inputForm.$error = {};
+                            $scope.ui.inputForm.$setPristine();
+                        })
+                        .error(Messages.showError);
+                });
+        };
+
+        $scope.resetAll = function() {
+            Confirm.confirm('Are you sure you want to undo all changes for current cache?')
+                .then(function() {
+                    $scope.backupItem = $scope.selectedItem ? angular.copy($scope.selectedItem) : prepareNewItem();
+                    $scope.ui.inputForm.$error = {};
+                    $scope.ui.inputForm.$setPristine();
+                });
+        };
+    }
+]];


[08/52] ignite git commit: Web Console beta-3.

Posted by ak...@apache.org.
http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/src/main/js/generator/generator-optional.js
----------------------------------------------------------------------
diff --git a/modules/web-console/src/main/js/generator/generator-optional.js b/modules/web-console/src/main/js/generator/generator-optional.js
deleted file mode 100644
index 61de1a2..0000000
--- a/modules/web-console/src/main/js/generator/generator-optional.js
+++ /dev/null
@@ -1,25 +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.
- */
-
-// Optional content generation entry point.
-const $generatorOptional = {};
-
-$generatorOptional.optionalContent = function(zip, cluster) { // eslint-disable-line no-unused-vars
-    // No-op.
-};
-
-export default $generatorOptional;

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/src/main/js/generator/generator-properties.js
----------------------------------------------------------------------
diff --git a/modules/web-console/src/main/js/generator/generator-properties.js b/modules/web-console/src/main/js/generator/generator-properties.js
deleted file mode 100644
index 4773f22..0000000
--- a/modules/web-console/src/main/js/generator/generator-properties.js
+++ /dev/null
@@ -1,150 +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.
- */
-
-// Properties generation entry point.
-const $generatorProperties = {};
-
-$generatorProperties.jdbcUrlTemplate = function(dialect) {
-    switch (dialect) {
-        case 'Oracle':
-            return 'jdbc:oracle:thin:@[host]:[port]:[database]';
-        case 'DB2':
-            return 'jdbc:db2://[host]:[port]/[database]';
-        case 'SQLServer':
-            return 'jdbc:sqlserver://[host]:[port][;databaseName=database]';
-        case 'MySQL':
-            return 'jdbc:mysql://[host]:[port]/[database]';
-        case 'PostgreSQL':
-            return 'jdbc:postgresql://[host]:[port]/[database]';
-        case 'H2':
-            return 'jdbc:h2:tcp://[host]/[database]';
-        default:
-    }
-
-    return 'jdbc:your_database';
-};
-
-/**
- * Generate properties file with properties stubs for stores data sources.
- *
- * @param cluster Configuration to process.
- * @param res Resulting output with generated properties.
- * @returns {string} Generated content.
- */
-$generatorProperties.dataSourcesProperties = function(cluster, res) {
-    const datasources = [];
-
-    if (cluster.caches && cluster.caches.length > 0) {
-        _.forEach(cluster.caches, function(cache) {
-            if (cache.cacheStoreFactory && cache.cacheStoreFactory.kind) {
-                const storeFactory = cache.cacheStoreFactory[cache.cacheStoreFactory.kind];
-
-                const dialect = storeFactory.connectVia ? (storeFactory.connectVia === 'DataSource' ? storeFactory.dialect : null) : storeFactory.dialect;
-
-                const connectViaUrl = cache.cacheStoreFactory.kind === 'CacheJdbcBlobStoreFactory' && storeFactory.connectVia === 'URL';
-
-                if (!res && (dialect || connectViaUrl)) {
-                    res = $generatorCommon.builder();
-
-                    res.line('# ' + $generatorCommon.mainComment());
-                }
-
-                if (dialect) {
-                    const beanId = storeFactory.dataSourceBean;
-
-                    const dsClsName = $generatorCommon.dataSourceClassName(dialect);
-
-                    const varType = res.importClass(dsClsName);
-
-                    const beanClassName = $generatorCommon.toJavaName(varType, storeFactory.dataSourceBean);
-
-                    if (!_.includes(datasources, beanClassName)) {
-                        datasources.push(beanClassName);
-
-                        res.needEmptyLine = true;
-
-                        switch (dialect) {
-                            case 'DB2':
-                                res.line(beanId + '.jdbc.server_name=YOUR_DATABASE_SERVER_NAME');
-                                res.line(beanId + '.jdbc.port_number=YOUR_JDBC_PORT_NUMBER');
-                                res.line(beanId + '.jdbc.driver_type=YOUR_JDBC_DRIVER_TYPE');
-                                res.line(beanId + '.jdbc.database_name=YOUR_DATABASE_NAME');
-
-                                break;
-
-                            default:
-                                res.line(beanId + '.jdbc.url=' + $generatorProperties.jdbcUrlTemplate(dialect));
-                        }
-
-                        res.line(beanId + '.jdbc.username=YOUR_USER_NAME');
-                        res.line(beanId + '.jdbc.password=YOUR_PASSWORD');
-                        res.line('');
-                    }
-                }
-
-                if (connectViaUrl)
-                    res.line('ds.' + storeFactory.user + '.password=YOUR_PASSWORD');
-            }
-        });
-    }
-
-    return res;
-};
-
-/**
- * Generate properties file with properties stubs for cluster SSL configuration.
- *
- * @param cluster Cluster to get SSL configuration.
- * @param res Optional configuration presentation builder object.
- * @returns Configuration presentation builder object
- */
-$generatorProperties.sslProperties = function(cluster, res) {
-    if (cluster.sslEnabled && cluster.sslContextFactory) {
-        if (!res) {
-            res = $generatorCommon.builder();
-
-            res.line('# ' + $generatorCommon.mainComment());
-        }
-
-        res.needEmptyLine = true;
-
-        if (_.isEmpty(cluster.sslContextFactory.keyStoreFilePath))
-            res.line('ssl.key.storage.password=YOUR_SSL_KEY_STORAGE_PASSWORD');
-
-        if (_.isEmpty(cluster.sslContextFactory.trustStoreFilePath))
-            res.line('ssl.trust.storage.password=YOUR_SSL_TRUST_STORAGE_PASSWORD');
-    }
-
-    return res;
-};
-
-/**
- * Generate properties file with all possible properties.
- *
- * @param cluster Cluster to get configurations.
- * @param res Optional configuration presentation builder object.
- * @returns Configuration presentation builder object
- */
-$generatorProperties.generateProperties = function(cluster, res) {
-    res = $generatorProperties.dataSourcesProperties(cluster, res);
-
-    res = $generatorProperties.sslProperties(cluster, res);
-
-    return res;
-};
-
-export default $generatorProperties;

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/src/main/js/generator/generator-readme.js
----------------------------------------------------------------------
diff --git a/modules/web-console/src/main/js/generator/generator-readme.js b/modules/web-console/src/main/js/generator/generator-readme.js
deleted file mode 100644
index 432f1e6..0000000
--- a/modules/web-console/src/main/js/generator/generator-readme.js
+++ /dev/null
@@ -1,85 +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.
- */
-
-// README.txt generation entry point.
-const $generatorReadme = {};
-
-$generatorReadme.generatedBy = function(res) {
-    res.line('Content of this folder was generated by Apache Ignite Web Console');
-    res.line('=================================================================');
-
-    res.needEmptyLine = true;
-};
-
-/**
- * Generate README.txt.
- *
- * @param res Resulting output with generated readme.
- * @returns {string} Generated content.
- */
-$generatorReadme.readme = function(res) {
-    if (!res)
-        res = $generatorCommon.builder();
-
-    $generatorReadme.generatedBy(res);
-
-    res.line('Project structure:');
-    res.line('    /config - this folder contains client and server XML configurations.');
-    res.line('    /jdbc-drivers - this folder should contains proprietary JDBC drivers.');
-    res.line('    /src - this folder contains generated java code.');
-    res.line('    /src/main/java/config - this folder contains generated java classes with cluster configuration from code.');
-    res.line('    /src/main/java/startup - this folder contains generated java classes with server and client nodes startup code.');
-    res.line('    /src/main/java/[model] - this optional folder will be named as package name for your POJO classes and contain generated POJO files.');
-    res.line('    /src/main/resources - this optional folder contains generated secret.properties file with security sensitive information if any.');
-    res.line('    Dockerfile - sample Docker file. With this file you could package Ignite deployment with all the dependencies into a standard container.');
-    res.line('    pom.xml - generated Maven project description, could be used to open generated project in IDE or build with Maven.');
-    res.line('    README.txt - this file.');
-
-    res.needEmptyLine = true;
-
-    res.line('Ignite ships with CacheJdbcPojoStore, which is out-of-the-box JDBC implementation of the IgniteCacheStore ');
-    res.line('interface, and automatically handles all the write-through and read-through logic.');
-
-    res.needEmptyLine = true;
-
-    res.line('You can use generated configuration and POJO classes as part of your application.');
-
-    res.needEmptyLine = true;
-
-    res.line('Note, in case of using proprietary JDBC drivers (Oracle, IBM DB2, Microsoft SQL Server)');
-    res.line('you should download them manually and copy into ./jdbc-drivers folder.');
-
-    return res;
-};
-
-/**
- * Generate README.txt for jdbc folder.
- *
- * @param res Resulting output with generated readme.
- * @returns {string} Generated content.
- */
-$generatorReadme.readmeJdbc = function(res) {
-    if (!res)
-        res = $generatorCommon.builder();
-
-    res.line('Proprietary JDBC drivers for databases like Oracle, IBM DB2, Microsoft SQL Server are not available on Maven Central repository.');
-    res.line('Drivers should be downloaded manually and copied to this folder.');
-
-    return res;
-};
-
-export default $generatorReadme;

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/src/main/js/generator/generator-xml.js
----------------------------------------------------------------------
diff --git a/modules/web-console/src/main/js/generator/generator-xml.js b/modules/web-console/src/main/js/generator/generator-xml.js
deleted file mode 100644
index efc8df8..0000000
--- a/modules/web-console/src/main/js/generator/generator-xml.js
+++ /dev/null
@@ -1,1978 +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.
- */
-
-// XML generation entry point.
-const $generatorXml = {};
-
-// Do XML escape.
-$generatorXml.escape = function(s) {
-    if (typeof (s) !== 'string')
-        return s;
-
-    return s.replace(/&/g, '&amp;').replace(/</g, '&lt;').replace(/>/g, '&gt;').replace(/"/g, '&quot;');
-};
-
-// Add constructor argument
-$generatorXml.constructorArg = function(res, ix, obj, propName, dflt, opt) {
-    const v = (obj ? obj[propName] : null) || dflt;
-
-    if ($generatorCommon.isDefinedAndNotEmpty(v))
-        res.line('<constructor-arg ' + (ix >= 0 ? 'index="' + ix + '" ' : '') + 'value="' + v + '"/>');
-    else if (!opt) {
-        res.startBlock('<constructor-arg ' + (ix >= 0 ? 'index="' + ix + '"' : '') + '>');
-        res.line('<null/>');
-        res.endBlock('</constructor-arg>');
-    }
-};
-
-// Add XML element.
-$generatorXml.element = function(res, tag, attr1, val1, attr2, val2) {
-    let elem = '<' + tag;
-
-    if (attr1)
-        elem += ' ' + attr1 + '="' + val1 + '"';
-
-    if (attr2)
-        elem += ' ' + attr2 + '="' + val2 + '"';
-
-    elem += '/>';
-
-    res.emptyLineIfNeeded();
-    res.line(elem);
-};
-
-// Add property.
-$generatorXml.property = function(res, obj, propName, setterName, dflt) {
-    if (!_.isNil(obj)) {
-        const val = obj[propName];
-
-        if ($generatorCommon.isDefinedAndNotEmpty(val)) {
-            const missDflt = _.isNil(dflt);
-
-            // Add to result if no default provided or value not equals to default.
-            if (missDflt || (!missDflt && val !== dflt)) {
-                $generatorXml.element(res, 'property', 'name', setterName ? setterName : propName, 'value', $generatorXml.escape(val));
-
-                return true;
-            }
-        }
-    }
-
-    return false;
-};
-
-// Add property for class name.
-$generatorXml.classNameProperty = function(res, obj, propName) {
-    const val = obj[propName];
-
-    if (!_.isNil(val))
-        $generatorXml.element(res, 'property', 'name', propName, 'value', $generatorCommon.JavaTypes.fullClassName(val));
-};
-
-// Add list property.
-$generatorXml.listProperty = function(res, obj, propName, listType, rowFactory) {
-    const val = obj[propName];
-
-    if (val && val.length > 0) {
-        res.emptyLineIfNeeded();
-
-        if (!listType)
-            listType = 'list';
-
-        if (!rowFactory)
-            rowFactory = (v) => '<value>' + $generatorXml.escape(v) + '</value>';
-
-        res.startBlock('<property name="' + propName + '">');
-        res.startBlock('<' + listType + '>');
-
-        _.forEach(val, (v) => res.line(rowFactory(v)));
-
-        res.endBlock('</' + listType + '>');
-        res.endBlock('</property>');
-
-        res.needEmptyLine = true;
-    }
-};
-
-// Add array property
-$generatorXml.arrayProperty = function(res, obj, propName, descr, rowFactory) {
-    const val = obj[propName];
-
-    if (val && val.length > 0) {
-        res.emptyLineIfNeeded();
-
-        if (!rowFactory)
-            rowFactory = (v) => '<bean class="' + v + '"/>';
-
-        res.startBlock('<property name="' + propName + '">');
-        res.startBlock('<list>');
-
-        _.forEach(val, (v) => res.append(rowFactory(v)));
-
-        res.endBlock('</list>');
-        res.endBlock('</property>');
-    }
-};
-
-/**
- * Add bean property with internal content.
- *
- * @param res Optional configuration presentation builder object.
- * @param bean Bean object for code generation.
- * @param beanPropName Name of property to set generated bean as value.
- * @param desc Bean metadata object.
- * @param createBeanAlthoughNoProps Always generate bean even it has no properties defined.
- */
-$generatorXml.beanProperty = function(res, bean, beanPropName, desc, createBeanAlthoughNoProps) {
-    const props = desc.fields;
-
-    if (bean && $generatorCommon.hasProperty(bean, props)) {
-        if (!createBeanAlthoughNoProps)
-            res.startSafeBlock();
-
-        res.emptyLineIfNeeded();
-        res.startBlock('<property name="' + beanPropName + '">');
-
-        if (createBeanAlthoughNoProps)
-            res.startSafeBlock();
-
-        res.startBlock('<bean class="' + desc.className + '">');
-
-        let hasData = false;
-
-        _.forIn(props, function(descr, propName) {
-            if (props.hasOwnProperty(propName)) {
-                if (descr) {
-                    switch (descr.type) {
-                        case 'list':
-                            $generatorXml.listProperty(res, bean, propName, descr.setterName);
-
-                            break;
-
-                        case 'array':
-                            $generatorXml.arrayProperty(res, bean, propName, descr);
-
-                            break;
-
-                        case 'propertiesAsList':
-                            const val = bean[propName];
-
-                            if (val && val.length > 0) {
-                                res.startBlock('<property name="' + propName + '">');
-                                res.startBlock('<props>');
-
-                                _.forEach(val, function(nameAndValue) {
-                                    const eqIndex = nameAndValue.indexOf('=');
-                                    if (eqIndex >= 0) {
-                                        res.line('<prop key="' + $generatorXml.escape(nameAndValue.substring(0, eqIndex)) + '">' +
-                                            $generatorXml.escape(nameAndValue.substr(eqIndex + 1)) + '</prop>');
-                                    }
-                                });
-
-                                res.endBlock('</props>');
-                                res.endBlock('</property>');
-
-                                hasData = true;
-                            }
-
-                            break;
-
-                        case 'bean':
-                            if ($generatorCommon.isDefinedAndNotEmpty(bean[propName])) {
-                                res.startBlock('<property name="' + propName + '">');
-                                res.line('<bean class="' + bean[propName] + '"/>');
-                                res.endBlock('</property>');
-
-                                hasData = true;
-                            }
-
-                            break;
-
-                        default:
-                            if ($generatorXml.property(res, bean, propName, descr.setterName, descr.dflt))
-                                hasData = true;
-                    }
-                }
-                else
-                    if ($generatorXml.property(res, bean, propName))
-                        hasData = true;
-            }
-        });
-
-        res.endBlock('</bean>');
-
-        if (createBeanAlthoughNoProps && !hasData) {
-            res.rollbackSafeBlock();
-
-            res.line('<bean class="' + desc.className + '"/>');
-        }
-
-        res.endBlock('</property>');
-
-        if (!createBeanAlthoughNoProps && !hasData)
-            res.rollbackSafeBlock();
-    }
-    else if (createBeanAlthoughNoProps) {
-        res.emptyLineIfNeeded();
-        res.startBlock('<property name="' + beanPropName + '">');
-        res.line('<bean class="' + desc.className + '"/>');
-        res.endBlock('</property>');
-    }
-};
-
-/**
- * Add bean property without internal content.
- *
- * @param res Optional configuration presentation builder object.
- * @param obj Object to take bean class name.
- * @param propName Property name.
- */
-$generatorXml.simpleBeanProperty = function(res, obj, propName) {
-    if (!_.isNil(obj)) {
-        const val = obj[propName];
-
-        if ($generatorCommon.isDefinedAndNotEmpty(val)) {
-            res.startBlock('<property name="' + propName + '">');
-            res.line('<bean class="' + val + '"/>');
-            res.endBlock('</property>');
-        }
-    }
-
-    return false;
-};
-
-// Generate eviction policy.
-$generatorXml.evictionPolicy = function(res, evtPlc, propName) {
-    if (evtPlc && evtPlc.kind) {
-        $generatorXml.beanProperty(res, evtPlc[evtPlc.kind.toUpperCase()], propName,
-            $generatorCommon.EVICTION_POLICIES[evtPlc.kind], true);
-    }
-};
-
-// Generate discovery.
-$generatorXml.clusterGeneral = function(cluster, res) {
-    if (!res)
-        res = $generatorCommon.builder();
-
-    $generatorXml.property(res, cluster, 'name', 'gridName');
-    $generatorXml.property(res, cluster, 'localHost');
-
-    if (cluster.discovery) {
-        res.startBlock('<property name="discoverySpi">');
-        res.startBlock('<bean class="org.apache.ignite.spi.discovery.tcp.TcpDiscoverySpi">');
-        res.startBlock('<property name="ipFinder">');
-
-        const d = cluster.discovery;
-
-        switch (d.kind) {
-            case 'Multicast':
-                res.startBlock('<bean class="org.apache.ignite.spi.discovery.tcp.ipfinder.multicast.TcpDiscoveryMulticastIpFinder">');
-
-                if (d.Multicast) {
-                    $generatorXml.property(res, d.Multicast, 'multicastGroup');
-                    $generatorXml.property(res, d.Multicast, 'multicastPort');
-                    $generatorXml.property(res, d.Multicast, 'responseWaitTime');
-                    $generatorXml.property(res, d.Multicast, 'addressRequestAttempts');
-                    $generatorXml.property(res, d.Multicast, 'localAddress');
-                    $generatorXml.listProperty(res, d.Multicast, 'addresses');
-                }
-
-                res.endBlock('</bean>');
-
-                break;
-
-            case 'Vm':
-                res.startBlock('<bean class="org.apache.ignite.spi.discovery.tcp.ipfinder.vm.TcpDiscoveryVmIpFinder">');
-
-                if (d.Vm)
-                    $generatorXml.listProperty(res, d.Vm, 'addresses');
-
-                res.endBlock('</bean>');
-
-                break;
-
-            case 'S3':
-                res.startBlock('<bean class="org.apache.ignite.spi.discovery.tcp.ipfinder.s3.TcpDiscoveryS3IpFinder">');
-
-                if (d.S3) {
-                    if (d.S3.bucketName)
-                        res.line('<property name="bucketName" value="' + $generatorXml.escape(d.S3.bucketName) + '"/>');
-                }
-
-                res.endBlock('</bean>');
-
-                break;
-
-            case 'Cloud':
-                res.startBlock('<bean class="org.apache.ignite.spi.discovery.tcp.ipfinder.cloud.TcpDiscoveryCloudIpFinder">');
-
-                if (d.Cloud) {
-                    $generatorXml.property(res, d.Cloud, 'credential');
-                    $generatorXml.property(res, d.Cloud, 'credentialPath');
-                    $generatorXml.property(res, d.Cloud, 'identity');
-                    $generatorXml.property(res, d.Cloud, 'provider');
-                    $generatorXml.listProperty(res, d.Cloud, 'regions');
-                    $generatorXml.listProperty(res, d.Cloud, 'zones');
-                }
-
-                res.endBlock('</bean>');
-
-                break;
-
-            case 'GoogleStorage':
-                res.startBlock('<bean class="org.apache.ignite.spi.discovery.tcp.ipfinder.gce.TcpDiscoveryGoogleStorageIpFinder">');
-
-                if (d.GoogleStorage) {
-                    $generatorXml.property(res, d.GoogleStorage, 'projectName');
-                    $generatorXml.property(res, d.GoogleStorage, 'bucketName');
-                    $generatorXml.property(res, d.GoogleStorage, 'serviceAccountP12FilePath');
-                    $generatorXml.property(res, d.GoogleStorage, 'serviceAccountId');
-                }
-
-                res.endBlock('</bean>');
-
-                break;
-
-            case 'Jdbc':
-                res.startBlock('<bean class="org.apache.ignite.spi.discovery.tcp.ipfinder.jdbc.TcpDiscoveryJdbcIpFinder">');
-
-                if (d.Jdbc)
-                    res.line('<property name="initSchema" value="' + (!_.isNil(d.Jdbc.initSchema) && d.Jdbc.initSchema) + '"/>');
-
-                res.endBlock('</bean>');
-
-                break;
-
-            case 'SharedFs':
-                res.startBlock('<bean class="org.apache.ignite.spi.discovery.tcp.ipfinder.sharedfs.TcpDiscoverySharedFsIpFinder">');
-
-                if (d.SharedFs)
-                    $generatorXml.property(res, d.SharedFs, 'path');
-
-                res.endBlock('</bean>');
-
-                break;
-
-            case 'ZooKeeper':
-                res.startBlock('<bean class="org.apache.ignite.spi.discovery.tcp.ipfinder.zk.TcpDiscoveryZookeeperIpFinder">');
-
-                if (d.ZooKeeper) {
-                    if ($generatorCommon.isDefinedAndNotEmpty(d.ZooKeeper.curator)) {
-                        res.startBlock('<property name="curator">');
-                        res.line('<bean class="' + d.ZooKeeper.curator + '"/>');
-                        res.endBlock('</property>');
-                    }
-
-                    $generatorXml.property(res, d.ZooKeeper, 'zkConnectionString');
-
-                    if (d.ZooKeeper.retryPolicy && d.ZooKeeper.retryPolicy.kind) {
-                        const kind = d.ZooKeeper.retryPolicy.kind;
-                        const retryPolicy = d.ZooKeeper.retryPolicy[kind];
-                        const customClassDefined = retryPolicy && $generatorCommon.isDefinedAndNotEmpty(retryPolicy.className);
-
-                        if (kind !== 'Custom' || customClassDefined)
-                            res.startBlock('<property name="retryPolicy">');
-
-                        switch (kind) {
-                            case 'ExponentialBackoff':
-                                res.startBlock('<bean class="org.apache.curator.retry.ExponentialBackoffRetry">');
-                                $generatorXml.constructorArg(res, 0, retryPolicy, 'baseSleepTimeMs', 1000);
-                                $generatorXml.constructorArg(res, 1, retryPolicy, 'maxRetries', 10);
-                                $generatorXml.constructorArg(res, 2, retryPolicy, 'maxSleepMs', null, true);
-                                res.endBlock('</bean>');
-
-                                break;
-
-                            case 'BoundedExponentialBackoff':
-                                res.startBlock('<bean class="org.apache.curator.retry.BoundedExponentialBackoffRetry">');
-                                $generatorXml.constructorArg(res, 0, retryPolicy, 'baseSleepTimeMs', 1000);
-                                $generatorXml.constructorArg(res, 1, retryPolicy, 'maxSleepTimeMs', 2147483647);
-                                $generatorXml.constructorArg(res, 2, retryPolicy, 'maxRetries', 10);
-                                res.endBlock('</bean>');
-
-                                break;
-
-                            case 'UntilElapsed':
-                                res.startBlock('<bean class="org.apache.curator.retry.RetryUntilElapsed">');
-                                $generatorXml.constructorArg(res, 0, retryPolicy, 'maxElapsedTimeMs', 60000);
-                                $generatorXml.constructorArg(res, 1, retryPolicy, 'sleepMsBetweenRetries', 1000);
-                                res.endBlock('</bean>');
-
-                                break;
-
-                            case 'NTimes':
-                                res.startBlock('<bean class="org.apache.curator.retry.RetryNTimes">');
-                                $generatorXml.constructorArg(res, 0, retryPolicy, 'n', 10);
-                                $generatorXml.constructorArg(res, 1, retryPolicy, 'sleepMsBetweenRetries', 1000);
-                                res.endBlock('</bean>');
-
-                                break;
-
-                            case 'OneTime':
-                                res.startBlock('<bean class="org.apache.curator.retry.RetryOneTime">');
-                                $generatorXml.constructorArg(res, 0, retryPolicy, 'sleepMsBetweenRetry', 1000);
-                                res.endBlock('</bean>');
-
-                                break;
-
-                            case 'Forever':
-                                res.startBlock('<bean class="org.apache.curator.retry.RetryForever">');
-                                $generatorXml.constructorArg(res, 0, retryPolicy, 'retryIntervalMs', 1000);
-                                res.endBlock('</bean>');
-
-                                break;
-
-                            case 'Custom':
-                                if (customClassDefined)
-                                    res.line('<bean class="' + retryPolicy.className + '"/>');
-
-                                break;
-
-                            default:
-                        }
-
-                        if (kind !== 'Custom' || customClassDefined)
-                            res.endBlock('</property>');
-                    }
-
-                    $generatorXml.property(res, d.ZooKeeper, 'basePath', null, '/services');
-                    $generatorXml.property(res, d.ZooKeeper, 'serviceName', null, 'ignite');
-                    $generatorXml.property(res, d.ZooKeeper, 'allowDuplicateRegistrations', null, false);
-                }
-
-                res.endBlock('</bean>');
-
-                break;
-
-            default:
-                res.line('Unknown discovery kind: ' + d.kind);
-        }
-
-        res.endBlock('</property>');
-
-        $generatorXml.clusterDiscovery(d, res);
-
-        res.endBlock('</bean>');
-        res.endBlock('</property>');
-
-        res.needEmptyLine = true;
-    }
-
-    return res;
-};
-
-// Generate atomics group.
-$generatorXml.clusterAtomics = function(atomics, res) {
-    if (!res)
-        res = $generatorCommon.builder();
-
-    if ($generatorCommon.hasAtLeastOneProperty(atomics, ['cacheMode', 'atomicSequenceReserveSize', 'backups'])) {
-        res.startSafeBlock();
-
-        res.emptyLineIfNeeded();
-
-        res.startBlock('<property name="atomicConfiguration">');
-        res.startBlock('<bean class="org.apache.ignite.configuration.AtomicConfiguration">');
-
-        const cacheMode = atomics.cacheMode ? atomics.cacheMode : 'PARTITIONED';
-
-        let hasData = cacheMode !== 'PARTITIONED';
-
-        $generatorXml.property(res, atomics, 'cacheMode', null, 'PARTITIONED');
-
-        hasData = $generatorXml.property(res, atomics, 'atomicSequenceReserveSize', null, 1000) || hasData;
-
-        if (cacheMode === 'PARTITIONED')
-            hasData = $generatorXml.property(res, atomics, 'backups', null, 0) || hasData;
-
-        res.endBlock('</bean>');
-        res.endBlock('</property>');
-
-        res.needEmptyLine = true;
-
-        if (!hasData)
-            res.rollbackSafeBlock();
-    }
-
-    return res;
-};
-
-// Generate binary group.
-$generatorXml.clusterBinary = function(binary, res) {
-    if (!res)
-        res = $generatorCommon.builder();
-
-    if ($generatorCommon.binaryIsDefined(binary)) {
-        res.startBlock('<property name="binaryConfiguration">');
-        res.startBlock('<bean class="org.apache.ignite.configuration.BinaryConfiguration">');
-
-        $generatorXml.simpleBeanProperty(res, binary, 'idMapper');
-        $generatorXml.simpleBeanProperty(res, binary, 'nameMapper');
-        $generatorXml.simpleBeanProperty(res, binary, 'serializer');
-
-        if ($generatorCommon.isDefinedAndNotEmpty(binary.typeConfigurations)) {
-            res.startBlock('<property name="typeConfigurations">');
-            res.startBlock('<list>');
-
-            _.forEach(binary.typeConfigurations, function(type) {
-                res.startBlock('<bean class="org.apache.ignite.binary.BinaryTypeConfiguration">');
-
-                $generatorXml.property(res, type, 'typeName');
-                $generatorXml.simpleBeanProperty(res, type, 'idMapper');
-                $generatorXml.simpleBeanProperty(res, type, 'nameMapper');
-                $generatorXml.simpleBeanProperty(res, type, 'serializer');
-                $generatorXml.property(res, type, 'enum', null, false);
-
-                res.endBlock('</bean>');
-            });
-
-            res.endBlock('</list>');
-            res.endBlock('</property>');
-        }
-
-        $generatorXml.property(res, binary, 'compactFooter', null, true);
-
-        res.endBlock('</bean>');
-        res.endBlock('</property>');
-
-        res.needEmptyLine = true;
-    }
-
-    return res;
-};
-
-// Generate collision group.
-$generatorXml.clusterCollision = function(collision, res) {
-    if (!res)
-        res = $generatorCommon.builder();
-
-    if (collision && collision.kind && collision.kind !== 'Noop') {
-        const spi = collision[collision.kind];
-
-        if (collision.kind !== 'Custom' || (spi && $generatorCommon.isDefinedAndNotEmpty(spi.class))) {
-            res.startBlock('<property name="collisionSpi">');
-
-            switch (collision.kind) {
-                case 'JobStealing':
-                    res.startBlock('<bean class="org.apache.ignite.spi.collision.jobstealing.JobStealingCollisionSpi">');
-                    $generatorXml.property(res, spi, 'activeJobsThreshold', null, 95);
-                    $generatorXml.property(res, spi, 'waitJobsThreshold', null, 0);
-                    $generatorXml.property(res, spi, 'messageExpireTime', null, 1000);
-                    $generatorXml.property(res, spi, 'maximumStealingAttempts', null, 5);
-                    $generatorXml.property(res, spi, 'stealingEnabled', null, true);
-
-                    if ($generatorCommon.isDefinedAndNotEmpty(spi.externalCollisionListener)) {
-                        res.needEmptyLine = true;
-
-                        res.startBlock('<property name="externalCollisionListener">');
-                        res.line('<bean class="' + spi.externalCollisionListener + ' "/>');
-                        res.endBlock('</property>');
-                    }
-
-                    if ($generatorCommon.isDefinedAndNotEmpty(spi.stealingAttributes)) {
-                        res.needEmptyLine = true;
-
-                        res.startBlock('<property name="stealingAttributes">');
-                        res.startBlock('<map>');
-
-                        _.forEach(spi.stealingAttributes, function(attr) {
-                            $generatorXml.element(res, 'entry', 'key', attr.name, 'value', attr.value);
-                        });
-
-                        res.endBlock('</map>');
-                        res.endBlock('</property>');
-                    }
-
-                    res.endBlock('</bean>');
-
-                    break;
-
-                case 'FifoQueue':
-                    res.startBlock('<bean class="org.apache.ignite.spi.collision.fifoqueue.FifoQueueCollisionSpi">');
-                    $generatorXml.property(res, spi, 'parallelJobsNumber');
-                    $generatorXml.property(res, spi, 'waitingJobsNumber');
-                    res.endBlock('</bean>');
-
-                    break;
-
-                case 'PriorityQueue':
-                    res.startBlock('<bean class="org.apache.ignite.spi.collision.priorityqueue.PriorityQueueCollisionSpi">');
-                    $generatorXml.property(res, spi, 'parallelJobsNumber');
-                    $generatorXml.property(res, spi, 'waitingJobsNumber');
-                    $generatorXml.property(res, spi, 'priorityAttributeKey', null, 'grid.task.priority');
-                    $generatorXml.property(res, spi, 'jobPriorityAttributeKey', null, 'grid.job.priority');
-                    $generatorXml.property(res, spi, 'defaultPriority', null, 0);
-                    $generatorXml.property(res, spi, 'starvationIncrement', null, 1);
-                    $generatorXml.property(res, spi, 'starvationPreventionEnabled', null, true);
-                    res.endBlock('</bean>');
-
-                    break;
-
-                case 'Custom':
-                    res.line('<bean class="' + spi.class + '"/>');
-
-                    break;
-
-                default:
-            }
-
-            res.endBlock('</property>');
-        }
-    }
-
-    return res;
-};
-
-// Generate communication group.
-$generatorXml.clusterCommunication = function(cluster, res) {
-    if (!res)
-        res = $generatorCommon.builder();
-
-    $generatorXml.beanProperty(res, cluster.communication, 'communicationSpi', $generatorCommon.COMMUNICATION_CONFIGURATION);
-
-    $generatorXml.property(res, cluster, 'networkTimeout', null, 5000);
-    $generatorXml.property(res, cluster, 'networkSendRetryDelay', null, 1000);
-    $generatorXml.property(res, cluster, 'networkSendRetryCount', null, 3);
-    $generatorXml.property(res, cluster, 'segmentCheckFrequency');
-    $generatorXml.property(res, cluster, 'waitForSegmentOnStart', null, false);
-    $generatorXml.property(res, cluster, 'discoveryStartupDelay', null, 60000);
-
-    res.needEmptyLine = true;
-
-    return res;
-};
-
-/**
- * XML generator for cluster's REST access configuration.
- *
- * @param connector Cluster REST connector configuration.
- * @param res Optional configuration presentation builder object.
- * @returns Configuration presentation builder object
- */
-$generatorXml.clusterConnector = function(connector, res) {
-    if (!res)
-        res = $generatorCommon.builder();
-
-    if (!_.isNil(connector) && connector.enabled) {
-        const cfg = _.cloneDeep($generatorCommon.CONNECTOR_CONFIGURATION);
-
-        if (connector.sslEnabled) {
-            cfg.fields.sslClientAuth = {dflt: false};
-            cfg.fields.sslFactory = {type: 'bean'};
-        }
-
-        $generatorXml.beanProperty(res, connector, 'connectorConfiguration', cfg, true);
-
-        res.needEmptyLine = true;
-    }
-
-    return res;
-};
-
-// Generate deployment group.
-$generatorXml.clusterDeployment = function(cluster, res) {
-    if (!res)
-        res = $generatorCommon.builder();
-
-    if ($generatorXml.property(res, cluster, 'deploymentMode', null, 'SHARED'))
-        res.needEmptyLine = true;
-
-    const p2pEnabled = cluster.peerClassLoadingEnabled;
-
-    if (!_.isNil(p2pEnabled)) {
-        $generatorXml.property(res, cluster, 'peerClassLoadingEnabled', null, false);
-
-        if (p2pEnabled) {
-            $generatorXml.property(res, cluster, 'peerClassLoadingMissedResourcesCacheSize', null, 100);
-            $generatorXml.property(res, cluster, 'peerClassLoadingThreadPoolSize', null, 2);
-            $generatorXml.listProperty(res, cluster, 'peerClassLoadingLocalClassPathExclude');
-        }
-
-        res.needEmptyLine = true;
-    }
-
-    return res;
-};
-
-// Generate discovery group.
-$generatorXml.clusterDiscovery = function(disco, res) {
-    if (!res)
-        res = $generatorCommon.builder();
-
-    if (disco) {
-        $generatorXml.property(res, disco, 'localAddress');
-        $generatorXml.property(res, disco, 'localPort', null, 47500);
-        $generatorXml.property(res, disco, 'localPortRange', null, 100);
-        if ($generatorCommon.isDefinedAndNotEmpty(disco.addressResolver))
-            $generatorXml.beanProperty(res, disco, 'addressResolver', {className: disco.addressResolver}, true);
-        $generatorXml.property(res, disco, 'socketTimeout', null, 5000);
-        $generatorXml.property(res, disco, 'ackTimeout', null, 5000);
-        $generatorXml.property(res, disco, 'maxAckTimeout', null, 600000);
-        $generatorXml.property(res, disco, 'networkTimeout', null, 5000);
-        $generatorXml.property(res, disco, 'joinTimeout', null, 0);
-        $generatorXml.property(res, disco, 'threadPriority', null, 10);
-        $generatorXml.property(res, disco, 'heartbeatFrequency', null, 2000);
-        $generatorXml.property(res, disco, 'maxMissedHeartbeats', null, 1);
-        $generatorXml.property(res, disco, 'maxMissedClientHeartbeats', null, 5);
-        $generatorXml.property(res, disco, 'topHistorySize', null, 1000);
-        if ($generatorCommon.isDefinedAndNotEmpty(disco.listener))
-            $generatorXml.beanProperty(res, disco, 'listener', {className: disco.listener}, true);
-        if ($generatorCommon.isDefinedAndNotEmpty(disco.dataExchange))
-            $generatorXml.beanProperty(res, disco, 'dataExchange', {className: disco.dataExchange}, true);
-        if ($generatorCommon.isDefinedAndNotEmpty(disco.metricsProvider))
-            $generatorXml.beanProperty(res, disco, 'metricsProvider', {className: disco.metricsProvider}, true);
-        $generatorXml.property(res, disco, 'reconnectCount', null, 10);
-        $generatorXml.property(res, disco, 'statisticsPrintFrequency', null, 0);
-        $generatorXml.property(res, disco, 'ipFinderCleanFrequency', null, 60000);
-        if ($generatorCommon.isDefinedAndNotEmpty(disco.authenticator))
-            $generatorXml.beanProperty(res, disco, 'authenticator', {className: disco.authenticator}, true);
-        $generatorXml.property(res, disco, 'forceServerMode', null, false);
-        $generatorXml.property(res, disco, 'clientReconnectDisabled', null, false);
-
-        res.needEmptyLine = true;
-    }
-
-    return res;
-};
-
-// Generate events group.
-$generatorXml.clusterEvents = function(cluster, res) {
-    if (!res)
-        res = $generatorCommon.builder();
-
-    if (cluster.includeEventTypes && cluster.includeEventTypes.length > 0) {
-        res.emptyLineIfNeeded();
-
-        res.startBlock('<property name="includeEventTypes">');
-
-        const evtGrps = angular.element(document.getElementById('app')).injector().get('igniteEventGroups');
-
-        if (cluster.includeEventTypes.length === 1) {
-            const evtGrp = _.find(evtGrps, {value: cluster.includeEventTypes[0]});
-
-            if (evtGrp)
-                res.line('<util:constant static-field="' + evtGrp.class + '.' + evtGrp.value + '"/>');
-        }
-        else {
-            res.startBlock('<list>');
-
-            _.forEach(cluster.includeEventTypes, (item, ix) => {
-                ix > 0 && res.line();
-
-                const evtGrp = _.find(evtGrps, {value: item});
-
-                if (evtGrp) {
-                    res.line('<!-- EventType.' + item + ' -->');
-
-                    _.forEach(evtGrp.events, (event) => res.line('<util:constant static-field="' + evtGrp.class + '.' + event + '"/>'));
-                }
-            });
-
-            res.endBlock('</list>');
-        }
-
-        res.endBlock('</property>');
-
-        res.needEmptyLine = true;
-    }
-
-    return res;
-};
-
-// Generate failover group.
-$generatorXml.clusterFailover = function(cluster, res) {
-    if (!res)
-        res = $generatorCommon.builder();
-
-    if ($generatorCommon.isDefinedAndNotEmpty(cluster.failoverSpi) && _.findIndex(cluster.failoverSpi, function(spi) {
-        return $generatorCommon.isDefinedAndNotEmpty(spi.kind) && (spi.kind !== 'Custom' || $generatorCommon.isDefinedAndNotEmpty(_.get(spi, spi.kind + '.class')));
-    }) >= 0) {
-        res.startBlock('<property name="failoverSpi">');
-        res.startBlock('<list>');
-
-        _.forEach(cluster.failoverSpi, function(spi) {
-            if (spi.kind && (spi.kind !== 'Custom' || $generatorCommon.isDefinedAndNotEmpty(_.get(spi, spi.kind + '.class')))) {
-                const maxAttempts = _.get(spi, spi.kind + '.maximumFailoverAttempts');
-
-                if ((spi.kind === 'JobStealing' || spi.kind === 'Always') && $generatorCommon.isDefinedAndNotEmpty(maxAttempts) && maxAttempts !== 5) {
-                    res.startBlock('<bean class="' + $generatorCommon.failoverSpiClass(spi) + '">');
-
-                    $generatorXml.property(res, spi[spi.kind], 'maximumFailoverAttempts', null, 5);
-
-                    res.endBlock('</bean>');
-                }
-                else
-                    res.line('<bean class="' + $generatorCommon.failoverSpiClass(spi) + '"/>');
-
-                res.needEmptyLine = true;
-            }
-        });
-
-        res.needEmptyLine = true;
-
-        res.endBlock('</list>');
-        res.endBlock('</property>');
-    }
-
-    return res;
-};
-
-// Generate marshaller group.
-$generatorXml.clusterLogger = function(logger, res) {
-    if (!res)
-        res = $generatorCommon.builder();
-
-    if ($generatorCommon.loggerConfigured(logger)) {
-        res.startBlock('<property name="gridLogger">');
-
-        const log = logger[logger.kind];
-
-        switch (logger.kind) {
-            case 'Log4j2':
-                res.startBlock('<bean class="org.apache.ignite.logger.log4j2.Log4J2Logger">');
-                res.line('<constructor-arg value="' + $generatorXml.escape(log.path) + '"/>');
-                $generatorXml.property(res, log, 'level');
-                res.endBlock('</bean>');
-
-                break;
-
-            case 'Null':
-                res.line('<bean class="org.apache.ignite.logger.NullLogger"/>');
-
-                break;
-
-            case 'Java':
-                res.line('<bean class="org.apache.ignite.logger.java.JavaLogger"/>');
-
-                break;
-
-            case 'JCL':
-                res.line('<bean class="org.apache.ignite.logger.jcl.JclLogger"/>');
-
-                break;
-
-            case 'SLF4J':
-                res.line('<bean class="org.apache.ignite.logger.slf4j.Slf4jLogger"/>');
-
-                break;
-
-            case 'Log4j':
-                if (log.mode === 'Default' && !$generatorCommon.isDefinedAndNotEmpty(log.level))
-                    res.line('<bean class="org.apache.ignite.logger.log4j.Log4JLogger"/>');
-                else {
-                    res.startBlock('<bean class="org.apache.ignite.logger.log4j.Log4JLogger">');
-
-                    if (log.mode === 'Path')
-                        res.line('<constructor-arg value="' + $generatorXml.escape(log.path) + '"/>');
-
-                    $generatorXml.property(res, log, 'level');
-                    res.endBlock('</bean>');
-                }
-
-                break;
-
-            case 'Custom':
-                res.line('<bean class="' + log.class + '"/>');
-
-                break;
-
-            default:
-        }
-
-        res.endBlock('</property>');
-
-        res.needEmptyLine = true;
-    }
-
-    return res;
-};
-
-// Generate marshaller group.
-$generatorXml.clusterMarshaller = function(cluster, res) {
-    if (!res)
-        res = $generatorCommon.builder();
-
-    const marshaller = cluster.marshaller;
-
-    if (marshaller && marshaller.kind)
-        $generatorXml.beanProperty(res, marshaller[marshaller.kind], 'marshaller', $generatorCommon.MARSHALLERS[marshaller.kind], true);
-
-    res.softEmptyLine();
-
-    $generatorXml.property(res, cluster, 'marshalLocalJobs', null, false);
-    $generatorXml.property(res, cluster, 'marshallerCacheKeepAliveTime', null, 10000);
-    $generatorXml.property(res, cluster, 'marshallerCacheThreadPoolSize', 'marshallerCachePoolSize');
-
-    res.needEmptyLine = true;
-
-    return res;
-};
-
-// Generate metrics group.
-$generatorXml.clusterMetrics = function(cluster, res) {
-    if (!res)
-        res = $generatorCommon.builder();
-
-    $generatorXml.property(res, cluster, 'metricsExpireTime');
-    $generatorXml.property(res, cluster, 'metricsHistorySize', null, 10000);
-    $generatorXml.property(res, cluster, 'metricsLogFrequency', null, 60000);
-    $generatorXml.property(res, cluster, 'metricsUpdateFrequency', null, 2000);
-
-    res.needEmptyLine = true;
-
-    return res;
-};
-
-// Generate swap group.
-$generatorXml.clusterSwap = function(cluster, res) {
-    if (!res)
-        res = $generatorCommon.builder();
-
-    if (cluster.swapSpaceSpi && cluster.swapSpaceSpi.kind === 'FileSwapSpaceSpi') {
-        $generatorXml.beanProperty(res, cluster.swapSpaceSpi.FileSwapSpaceSpi, 'swapSpaceSpi',
-            $generatorCommon.SWAP_SPACE_SPI, true);
-
-        res.needEmptyLine = true;
-    }
-
-    return res;
-};
-
-// Generate time group.
-$generatorXml.clusterTime = function(cluster, res) {
-    if (!res)
-        res = $generatorCommon.builder();
-
-    $generatorXml.property(res, cluster, 'clockSyncSamples', null, 8);
-    $generatorXml.property(res, cluster, 'clockSyncFrequency', null, 120000);
-    $generatorXml.property(res, cluster, 'timeServerPortBase', null, 31100);
-    $generatorXml.property(res, cluster, 'timeServerPortRange', null, 100);
-
-    res.needEmptyLine = true;
-
-    return res;
-};
-
-// Generate thread pools group.
-$generatorXml.clusterPools = function(cluster, res) {
-    if (!res)
-        res = $generatorCommon.builder();
-
-    $generatorXml.property(res, cluster, 'publicThreadPoolSize');
-    $generatorXml.property(res, cluster, 'systemThreadPoolSize');
-    $generatorXml.property(res, cluster, 'managementThreadPoolSize');
-    $generatorXml.property(res, cluster, 'igfsThreadPoolSize');
-    $generatorXml.property(res, cluster, 'rebalanceThreadPoolSize');
-
-    res.needEmptyLine = true;
-
-    return res;
-};
-
-// Generate transactions group.
-$generatorXml.clusterTransactions = function(transactionConfiguration, res) {
-    if (!res)
-        res = $generatorCommon.builder();
-
-    $generatorXml.beanProperty(res, transactionConfiguration, 'transactionConfiguration', $generatorCommon.TRANSACTION_CONFIGURATION, false);
-
-    res.needEmptyLine = true;
-
-    return res;
-};
-
-// Generate user attributes group.
-$generatorXml.clusterUserAttributes = function(cluster, res) {
-    if (!res)
-        res = $generatorCommon.builder();
-
-    if ($generatorCommon.isDefinedAndNotEmpty(cluster.attributes)) {
-        res.startBlock('<property name="userAttributes">');
-        res.startBlock('<map>');
-
-        _.forEach(cluster.attributes, function(attr) {
-            $generatorXml.element(res, 'entry', 'key', attr.name, 'value', attr.value);
-        });
-
-        res.endBlock('</map>');
-        res.endBlock('</property>');
-    }
-
-    res.needEmptyLine = true;
-
-    return res;
-};
-
-/**
- * XML generator for cluster's SSL configuration.
- *
- * @param cluster Cluster to get SSL configuration.
- * @param res Optional configuration presentation builder object.
- * @returns Configuration presentation builder object
- */
-$generatorXml.clusterSsl = function(cluster, res) {
-    if (!res)
-        res = $generatorCommon.builder();
-
-    if (cluster.sslEnabled && !_.isNil(cluster.sslContextFactory)) {
-        let sslFactory;
-
-        if (_.isEmpty(cluster.sslContextFactory.keyStoreFilePath) && _.isEmpty(cluster.sslContextFactory.trustStoreFilePath))
-            sslFactory = cluster.sslContextFactory;
-        else {
-            sslFactory = _.clone(cluster.sslContextFactory);
-
-            sslFactory.keyStorePassword = _.isEmpty(cluster.sslContextFactory.keyStoreFilePath) ? null : '${ssl.key.storage.password}';
-            sslFactory.trustStorePassword = _.isEmpty(cluster.sslContextFactory.trustStoreFilePath) ? null : '${ssl.trust.storage.password}';
-        }
-
-        const propsDesc = $generatorCommon.isDefinedAndNotEmpty(cluster.sslContextFactory.trustManagers) ?
-            $generatorCommon.SSL_CONFIGURATION_TRUST_MANAGER_FACTORY :
-            $generatorCommon.SSL_CONFIGURATION_TRUST_FILE_FACTORY;
-
-        $generatorXml.beanProperty(res, sslFactory, 'sslContextFactory', propsDesc, true);
-
-        res.needEmptyLine = true;
-    }
-
-    return res;
-};
-
-// Generate cache general group.
-$generatorXml.cacheGeneral = function(cache, res) {
-    if (!res)
-        res = $generatorCommon.builder();
-
-    $generatorXml.property(res, cache, 'name');
-
-    $generatorXml.property(res, cache, 'cacheMode');
-    $generatorXml.property(res, cache, 'atomicityMode');
-
-    if (cache.cacheMode === 'PARTITIONED' && $generatorXml.property(res, cache, 'backups'))
-        $generatorXml.property(res, cache, 'readFromBackup');
-
-    $generatorXml.property(res, cache, 'copyOnRead');
-
-    if (cache.cacheMode === 'PARTITIONED' && cache.atomicityMode === 'TRANSACTIONAL')
-        $generatorXml.property(res, cache, 'invalidate');
-
-    res.needEmptyLine = true;
-
-    return res;
-};
-
-// Generate cache memory group.
-$generatorXml.cacheMemory = function(cache, res) {
-    if (!res)
-        res = $generatorCommon.builder();
-
-    $generatorXml.property(res, cache, 'memoryMode', null, 'ONHEAP_TIERED');
-    $generatorXml.property(res, cache, 'offHeapMaxMemory', null, -1);
-
-    res.softEmptyLine();
-
-    $generatorXml.evictionPolicy(res, cache.evictionPolicy, 'evictionPolicy');
-
-    res.softEmptyLine();
-
-    $generatorXml.property(res, cache, 'startSize', null, 1500000);
-    $generatorXml.property(res, cache, 'swapEnabled', null, false);
-
-    res.needEmptyLine = true;
-
-    return res;
-};
-
-// Generate cache query & indexing group.
-$generatorXml.cacheQuery = function(cache, res) {
-    if (!res)
-        res = $generatorCommon.builder();
-
-    $generatorXml.property(res, cache, 'sqlSchema');
-    $generatorXml.property(res, cache, 'sqlOnheapRowCacheSize', null, 10240);
-    $generatorXml.property(res, cache, 'longQueryWarningTimeout', null, 3000);
-
-    const indexedTypes = _.filter(cache.domains, (domain) => domain.queryMetadata === 'Annotations');
-
-    if (indexedTypes.length > 0) {
-        res.startBlock('<property name="indexedTypes">');
-        res.startBlock('<list>');
-
-        _.forEach(indexedTypes, function(domain) {
-            res.line('<value>' + $generatorCommon.JavaTypes.fullClassName(domain.keyType) + '</value>');
-            res.line('<value>' + $generatorCommon.JavaTypes.fullClassName(domain.valueType) + '</value>');
-        });
-
-        res.endBlock('</list>');
-        res.endBlock('</property>');
-    }
-
-    res.softEmptyLine();
-
-    $generatorXml.listProperty(res, cache, 'sqlFunctionClasses');
-
-    res.softEmptyLine();
-
-    $generatorXml.property(res, cache, 'snapshotableIndex', null, false);
-    $generatorXml.property(res, cache, 'sqlEscapeAll', null, false);
-
-    res.needEmptyLine = true;
-
-    return res;
-};
-
-// Generate cache store group.
-$generatorXml.cacheStore = function(cache, domains, res) {
-    if (!res)
-        res = $generatorCommon.builder();
-
-    if (cache.cacheStoreFactory && cache.cacheStoreFactory.kind) {
-        const factoryKind = cache.cacheStoreFactory.kind;
-
-        const storeFactory = cache.cacheStoreFactory[factoryKind];
-
-        if (storeFactory) {
-            if (factoryKind === 'CacheJdbcPojoStoreFactory') {
-                res.startBlock('<property name="cacheStoreFactory">');
-                res.startBlock('<bean class="org.apache.ignite.cache.store.jdbc.CacheJdbcPojoStoreFactory">');
-
-                $generatorXml.property(res, storeFactory, 'dataSourceBean');
-
-                res.startBlock('<property name="dialect">');
-                res.line('<bean class="' + $generatorCommon.jdbcDialectClassName(storeFactory.dialect) + '"/>');
-                res.endBlock('</property>');
-
-                const domainConfigs = _.filter(domains, function(domain) {
-                    return $generatorCommon.isDefinedAndNotEmpty(domain.databaseTable);
-                });
-
-                if ($generatorCommon.isDefinedAndNotEmpty(domainConfigs)) {
-                    res.startBlock('<property name="types">');
-                    res.startBlock('<list>');
-
-                    _.forEach(domainConfigs, function(domain) {
-                        res.startBlock('<bean class="org.apache.ignite.cache.store.jdbc.JdbcType">');
-
-                        $generatorXml.property(res, cache, 'name', 'cacheName');
-
-                        $generatorXml.classNameProperty(res, domain, 'keyType');
-                        $generatorXml.property(res, domain, 'valueType');
-
-                        $generatorXml.domainStore(domain, res);
-
-                        res.endBlock('</bean>');
-                    });
-
-                    res.endBlock('</list>');
-                    res.endBlock('</property>');
-                }
-
-                res.endBlock('</bean>');
-                res.endBlock('</property>');
-            }
-            else if (factoryKind === 'CacheJdbcBlobStoreFactory') {
-                res.startBlock('<property name="cacheStoreFactory">');
-                res.startBlock('<bean class="org.apache.ignite.cache.store.jdbc.CacheJdbcBlobStoreFactory">');
-
-                if (storeFactory.connectVia === 'DataSource')
-                    $generatorXml.property(res, storeFactory, 'dataSourceBean');
-                else {
-                    $generatorXml.property(res, storeFactory, 'connectionUrl');
-                    $generatorXml.property(res, storeFactory, 'user');
-                    res.line('<property name="password" value="${ds.' + storeFactory.user + '.password}"/>');
-                }
-
-                $generatorXml.property(res, storeFactory, 'initSchema');
-                $generatorXml.property(res, storeFactory, 'createTableQuery');
-                $generatorXml.property(res, storeFactory, 'loadQuery');
-                $generatorXml.property(res, storeFactory, 'insertQuery');
-                $generatorXml.property(res, storeFactory, 'updateQuery');
-                $generatorXml.property(res, storeFactory, 'deleteQuery');
-
-                res.endBlock('</bean>');
-                res.endBlock('</property>');
-            }
-            else
-                $generatorXml.beanProperty(res, storeFactory, 'cacheStoreFactory', $generatorCommon.STORE_FACTORIES[factoryKind], true);
-
-            if (storeFactory.dataSourceBean && (storeFactory.connectVia ? (storeFactory.connectVia === 'DataSource' ? storeFactory.dialect : null) : storeFactory.dialect)) {
-                if (_.findIndex(res.datasources, (ds) => ds.dataSourceBean === storeFactory.dataSourceBean) < 0) {
-                    res.datasources.push({
-                        dataSourceBean: storeFactory.dataSourceBean,
-                        className: $generatorCommon.DATA_SOURCES[storeFactory.dialect],
-                        dialect: storeFactory.dialect
-                    });
-                }
-            }
-        }
-    }
-
-    res.softEmptyLine();
-
-    $generatorXml.property(res, cache, 'storeKeepBinary', null, false);
-    $generatorXml.property(res, cache, 'loadPreviousValue', null, false);
-    $generatorXml.property(res, cache, 'readThrough', null, false);
-    $generatorXml.property(res, cache, 'writeThrough', null, false);
-
-    res.softEmptyLine();
-
-    if (cache.writeBehindEnabled) {
-        $generatorXml.property(res, cache, 'writeBehindEnabled', null, false);
-        $generatorXml.property(res, cache, 'writeBehindBatchSize', null, 512);
-        $generatorXml.property(res, cache, 'writeBehindFlushSize', null, 10240);
-        $generatorXml.property(res, cache, 'writeBehindFlushFrequency', null, 5000);
-        $generatorXml.property(res, cache, 'writeBehindFlushThreadCount', null, 1);
-    }
-
-    res.needEmptyLine = true;
-
-    return res;
-};
-
-// Generate cache concurrency group.
-$generatorXml.cacheConcurrency = function(cache, res) {
-    if (!res)
-        res = $generatorCommon.builder();
-
-    $generatorXml.property(res, cache, 'maxConcurrentAsyncOperations', null, 500);
-    $generatorXml.property(res, cache, 'defaultLockTimeout', null, 0);
-    $generatorXml.property(res, cache, 'atomicWriteOrderMode');
-    $generatorXml.property(res, cache, 'writeSynchronizationMode', null, 'PRIMARY_SYNC');
-
-    res.needEmptyLine = true;
-
-    return res;
-};
-
-// Generate cache rebalance group.
-$generatorXml.cacheRebalance = function(cache, res) {
-    if (!res)
-        res = $generatorCommon.builder();
-
-    if (cache.cacheMode !== 'LOCAL') {
-        $generatorXml.property(res, cache, 'rebalanceMode', null, 'ASYNC');
-        $generatorXml.property(res, cache, 'rebalanceThreadPoolSize', null, 1);
-        $generatorXml.property(res, cache, 'rebalanceBatchSize', null, 524288);
-        $generatorXml.property(res, cache, 'rebalanceBatchesPrefetchCount', null, 2);
-        $generatorXml.property(res, cache, 'rebalanceOrder', null, 0);
-        $generatorXml.property(res, cache, 'rebalanceDelay', null, 0);
-        $generatorXml.property(res, cache, 'rebalanceTimeout', null, 10000);
-        $generatorXml.property(res, cache, 'rebalanceThrottle', null, 0);
-    }
-
-    res.softEmptyLine();
-
-    if (cache.igfsAffinnityGroupSize) {
-        res.startBlock('<property name="affinityMapper">');
-        res.startBlock('<bean class="org.apache.ignite.igfs.IgfsGroupDataBlocksKeyMapper">');
-        $generatorXml.constructorArg(res, -1, cache, 'igfsAffinnityGroupSize');
-        res.endBlock('</bean>');
-        res.endBlock('</property>');
-    }
-
-    return res;
-};
-
-// Generate cache server near cache group.
-$generatorXml.cacheServerNearCache = function(cache, res) {
-    if (!res)
-        res = $generatorCommon.builder();
-
-    if (cache.cacheMode === 'PARTITIONED' && cache.nearCacheEnabled) {
-        res.emptyLineIfNeeded();
-
-        res.startBlock('<property name="nearConfiguration">');
-        res.startBlock('<bean class="org.apache.ignite.configuration.NearCacheConfiguration">');
-
-        if (cache.nearConfiguration) {
-            if (cache.nearConfiguration.nearStartSize)
-                $generatorXml.property(res, cache.nearConfiguration, 'nearStartSize', null, 375000);
-
-            $generatorXml.evictionPolicy(res, cache.nearConfiguration.nearEvictionPolicy, 'nearEvictionPolicy');
-        }
-
-        res.endBlock('</bean>');
-        res.endBlock('</property>');
-    }
-
-    res.needEmptyLine = true;
-
-    return res;
-};
-
-// Generate cache statistics group.
-$generatorXml.cacheStatistics = function(cache, res) {
-    if (!res)
-        res = $generatorCommon.builder();
-
-    $generatorXml.property(res, cache, 'statisticsEnabled', null, false);
-    $generatorXml.property(res, cache, 'managementEnabled', null, false);
-
-    res.needEmptyLine = true;
-
-    return res;
-};
-
-// Generate domain model query fields.
-$generatorXml.domainModelQueryFields = function(res, domain) {
-    const fields = domain.fields;
-
-    if (fields && fields.length > 0) {
-        res.emptyLineIfNeeded();
-
-        res.startBlock('<property name="fields">');
-        res.startBlock('<map>');
-
-        _.forEach(fields, function(field) {
-            $generatorXml.element(res, 'entry', 'key', field.name, 'value', $generatorCommon.JavaTypes.fullClassName(field.className));
-        });
-
-        res.endBlock('</map>');
-        res.endBlock('</property>');
-
-        res.needEmptyLine = true;
-    }
-};
-
-// Generate domain model query fields.
-$generatorXml.domainModelQueryAliases = function(res, domain) {
-    const aliases = domain.aliases;
-
-    if (aliases && aliases.length > 0) {
-        res.emptyLineIfNeeded();
-
-        res.startBlock('<property name="aliases">');
-        res.startBlock('<map>');
-
-        _.forEach(aliases, function(alias) {
-            $generatorXml.element(res, 'entry', 'key', alias.field, 'value', alias.alias);
-        });
-
-        res.endBlock('</map>');
-        res.endBlock('</property>');
-
-        res.needEmptyLine = true;
-    }
-};
-
-// Generate domain model indexes.
-$generatorXml.domainModelQueryIndexes = function(res, domain) {
-    const indexes = domain.indexes;
-
-    if (indexes && indexes.length > 0) {
-        res.emptyLineIfNeeded();
-
-        res.startBlock('<property name="indexes">');
-        res.startBlock('<list>');
-
-        _.forEach(indexes, function(index) {
-            res.startBlock('<bean class="org.apache.ignite.cache.QueryIndex">');
-
-            $generatorXml.property(res, index, 'name');
-            $generatorXml.property(res, index, 'indexType');
-
-            const fields = index.fields;
-
-            if (fields && fields.length > 0) {
-                res.startBlock('<property name="fields">');
-                res.startBlock('<map>');
-
-                _.forEach(fields, function(field) {
-                    $generatorXml.element(res, 'entry', 'key', field.name, 'value', field.direction);
-                });
-
-                res.endBlock('</map>');
-                res.endBlock('</property>');
-            }
-
-            res.endBlock('</bean>');
-        });
-
-        res.endBlock('</list>');
-        res.endBlock('</property>');
-
-        res.needEmptyLine = true;
-    }
-};
-
-// Generate domain model db fields.
-$generatorXml.domainModelDatabaseFields = function(res, domain, fieldProp) {
-    const fields = domain[fieldProp];
-
-    if (fields && fields.length > 0) {
-        res.emptyLineIfNeeded();
-
-        res.startBlock('<property name="' + fieldProp + '">');
-
-        res.startBlock('<list>');
-
-        _.forEach(fields, function(field) {
-            res.startBlock('<bean class="org.apache.ignite.cache.store.jdbc.JdbcTypeField">');
-
-            $generatorXml.property(res, field, 'databaseFieldName');
-
-            res.startBlock('<property name="databaseFieldType">');
-            res.line('<util:constant static-field="java.sql.Types.' + field.databaseFieldType + '"/>');
-            res.endBlock('</property>');
-
-            $generatorXml.property(res, field, 'javaFieldName');
-
-            $generatorXml.classNameProperty(res, field, 'javaFieldType');
-
-            res.endBlock('</bean>');
-        });
-
-        res.endBlock('</list>');
-        res.endBlock('</property>');
-
-        res.needEmptyLine = true;
-    }
-};
-
-// Generate domain model general group.
-$generatorXml.domainModelGeneral = function(domain, res) {
-    if (!res)
-        res = $generatorCommon.builder();
-
-    switch ($generatorCommon.domainQueryMetadata(domain)) {
-        case 'Annotations':
-            if ($generatorCommon.isDefinedAndNotEmpty(domain.keyType) || $generatorCommon.isDefinedAndNotEmpty(domain.valueType)) {
-                res.startBlock('<property name="indexedTypes">');
-                res.startBlock('<list>');
-
-                if ($generatorCommon.isDefinedAndNotEmpty(domain.keyType))
-                    res.line('<value>' + $generatorCommon.JavaTypes.fullClassName(domain.keyType) + '</value>');
-                else
-                    res.line('<value>???</value>');
-
-                if ($generatorCommon.isDefinedAndNotEmpty(domain.valueType))
-                    res.line('<value>' + $generatorCommon.JavaTypes.fullClassName(domain.valueType) + '</value>');
-                else
-                    res.line('<value>>???</value>');
-
-                res.endBlock('</list>');
-                res.endBlock('</property>');
-            }
-
-            break;
-
-        case 'Configuration':
-            $generatorXml.classNameProperty(res, domain, 'keyType');
-            $generatorXml.property(res, domain, 'valueType');
-
-            break;
-
-        default:
-    }
-
-    res.needEmptyLine = true;
-
-    return res;
-};
-
-// Generate domain model for query group.
-$generatorXml.domainModelQuery = function(domain, res) {
-    if (!res)
-        res = $generatorCommon.builder();
-
-    if ($generatorCommon.domainQueryMetadata(domain) === 'Configuration') {
-        $generatorXml.domainModelQueryFields(res, domain);
-        $generatorXml.domainModelQueryAliases(res, domain);
-        $generatorXml.domainModelQueryIndexes(res, domain);
-
-        res.needEmptyLine = true;
-    }
-
-    return res;
-};
-
-// Generate domain model for store group.
-$generatorXml.domainStore = function(domain, res) {
-    if (!res)
-        res = $generatorCommon.builder();
-
-    $generatorXml.property(res, domain, 'databaseSchema');
-    $generatorXml.property(res, domain, 'databaseTable');
-
-    res.softEmptyLine();
-
-    $generatorXml.domainModelDatabaseFields(res, domain, 'keyFields');
-    $generatorXml.domainModelDatabaseFields(res, domain, 'valueFields');
-
-    res.needEmptyLine = true;
-
-    return res;
-};
-
-$generatorXml.cacheQueryMetadata = function(domain, res) {
-    if (!res)
-        res = $generatorCommon.builder();
-
-    res.startBlock('<bean class="org.apache.ignite.cache.QueryEntity">');
-
-    $generatorXml.classNameProperty(res, domain, 'keyType');
-    $generatorXml.property(res, domain, 'valueType');
-
-    $generatorXml.domainModelQuery(domain, res);
-
-    res.endBlock('</bean>');
-
-    res.needEmptyLine = true;
-
-    return res;
-};
-
-// Generate domain models configs.
-$generatorXml.cacheDomains = function(domains, res) {
-    if (!res)
-        res = $generatorCommon.builder();
-
-    const domainConfigs = _.filter(domains, function(domain) {
-        return $generatorCommon.domainQueryMetadata(domain) === 'Configuration' &&
-            $generatorCommon.isDefinedAndNotEmpty(domain.fields);
-    });
-
-    if ($generatorCommon.isDefinedAndNotEmpty(domainConfigs)) {
-        res.emptyLineIfNeeded();
-
-        res.startBlock('<property name="queryEntities">');
-        res.startBlock('<list>');
-
-        _.forEach(domainConfigs, function(domain) {
-            $generatorXml.cacheQueryMetadata(domain, res);
-        });
-
-        res.endBlock('</list>');
-        res.endBlock('</property>');
-    }
-
-    return res;
-};
-
-// Generate cache configs.
-$generatorXml.cache = function(cache, res) {
-    if (!res)
-        res = $generatorCommon.builder();
-
-    res.startBlock('<bean class="org.apache.ignite.configuration.CacheConfiguration">');
-
-    $generatorXml.cacheConfiguration(cache, res);
-
-    res.endBlock('</bean>');
-
-    return res;
-};
-
-// Generate cache configs.
-$generatorXml.cacheConfiguration = function(cache, res) {
-    if (!res)
-        res = $generatorCommon.builder();
-
-    $generatorXml.cacheGeneral(cache, res);
-    $generatorXml.cacheMemory(cache, res);
-    $generatorXml.cacheQuery(cache, res);
-    $generatorXml.cacheStore(cache, cache.domains, res);
-    $generatorXml.cacheConcurrency(cache, res);
-    $generatorXml.cacheRebalance(cache, res);
-    $generatorXml.cacheServerNearCache(cache, res);
-    $generatorXml.cacheStatistics(cache, res);
-    $generatorXml.cacheDomains(cache.domains, res);
-
-    return res;
-};
-
-// Generate caches configs.
-$generatorXml.clusterCaches = function(caches, igfss, isSrvCfg, res) {
-    if (!res)
-        res = $generatorCommon.builder();
-
-    if ($generatorCommon.isDefinedAndNotEmpty(caches) || (isSrvCfg && $generatorCommon.isDefinedAndNotEmpty(igfss))) {
-        res.emptyLineIfNeeded();
-
-        res.startBlock('<property name="cacheConfiguration">');
-        res.startBlock('<list>');
-
-        _.forEach(caches, function(cache) {
-            $generatorXml.cache(cache, res);
-
-            res.needEmptyLine = true;
-        });
-
-        if (isSrvCfg) {
-            _.forEach(igfss, (igfs) => {
-                $generatorXml.cache($generatorCommon.igfsDataCache(igfs), res);
-
-                res.needEmptyLine = true;
-
-                $generatorXml.cache($generatorCommon.igfsMetaCache(igfs), res);
-
-                res.needEmptyLine = true;
-            });
-        }
-
-        res.endBlock('</list>');
-        res.endBlock('</property>');
-
-        res.needEmptyLine = true;
-    }
-
-    return res;
-};
-
-// Generate IGFSs configs.
-$generatorXml.igfss = function(igfss, res) {
-    if (!res)
-        res = $generatorCommon.builder();
-
-    if ($generatorCommon.isDefinedAndNotEmpty(igfss)) {
-        res.emptyLineIfNeeded();
-
-        res.startBlock('<property name="fileSystemConfiguration">');
-        res.startBlock('<list>');
-
-        _.forEach(igfss, function(igfs) {
-            res.startBlock('<bean class="org.apache.ignite.configuration.FileSystemConfiguration">');
-
-            $generatorXml.igfsGeneral(igfs, res);
-            $generatorXml.igfsIPC(igfs, res);
-            $generatorXml.igfsFragmentizer(igfs, res);
-            $generatorXml.igfsDualMode(igfs, res);
-            $generatorXml.igfsSecondFS(igfs, res);
-            $generatorXml.igfsMisc(igfs, res);
-
-            res.endBlock('</bean>');
-
-            res.needEmptyLine = true;
-        });
-
-        res.endBlock('</list>');
-        res.endBlock('</property>');
-
-        res.needEmptyLine = true;
-    }
-
-    return res;
-};
-
-// Generate IGFS IPC configuration.
-$generatorXml.igfsIPC = function(igfs, res) {
-    if (!res)
-        res = $generatorCommon.builder();
-
-    if (igfs.ipcEndpointEnabled) {
-        $generatorXml.beanProperty(res, igfs.ipcEndpointConfiguration, 'ipcEndpointConfiguration', $generatorCommon.IGFS_IPC_CONFIGURATION, true);
-
-        res.needEmptyLine = true;
-    }
-
-    return res;
-};
-
-// Generate IGFS fragmentizer configuration.
-$generatorXml.igfsFragmentizer = function(igfs, res) {
-    if (!res)
-        res = $generatorCommon.builder();
-
-    if (igfs.fragmentizerEnabled) {
-        $generatorXml.property(res, igfs, 'fragmentizerConcurrentFiles', null, 0);
-        $generatorXml.property(res, igfs, 'fragmentizerThrottlingBlockLength', null, 16777216);
-        $generatorXml.property(res, igfs, 'fragmentizerThrottlingDelay', null, 200);
-
-        res.needEmptyLine = true;
-    }
-    else
-        $generatorXml.property(res, igfs, 'fragmentizerEnabled');
-
-    return res;
-};
-
-// Generate IGFS dual mode configuration.
-$generatorXml.igfsDualMode = function(igfs, res) {
-    if (!res)
-        res = $generatorCommon.builder();
-
-    $generatorXml.property(res, igfs, 'dualModeMaxPendingPutsSize', null, 0);
-
-    if ($generatorCommon.isDefinedAndNotEmpty(igfs.dualModePutExecutorService)) {
-        res.startBlock('<property name="dualModePutExecutorService">');
-        res.line('<bean class="' + igfs.dualModePutExecutorService + '"/>');
-        res.endBlock('</property>');
-    }
-
-    $generatorXml.property(res, igfs, 'dualModePutExecutorServiceShutdown', null, false);
-
-    res.needEmptyLine = true;
-
-    return res;
-};
-
-$generatorXml.igfsSecondFS = function(igfs, res) {
-    if (!res)
-        res = $generatorCommon.builder();
-
-    if (igfs.secondaryFileSystemEnabled) {
-        const secondFs = igfs.secondaryFileSystem || {};
-
-        res.startBlock('<property name="secondaryFileSystem">');
-
-        res.startBlock('<bean class="org.apache.ignite.hadoop.fs.IgniteHadoopIgfsSecondaryFileSystem">');
-
-        const nameDefined = $generatorCommon.isDefinedAndNotEmpty(secondFs.userName);
-        const cfgDefined = $generatorCommon.isDefinedAndNotEmpty(secondFs.cfgPath);
-
-        $generatorXml.constructorArg(res, 0, secondFs, 'uri');
-
-        if (cfgDefined || nameDefined)
-            $generatorXml.constructorArg(res, 1, secondFs, 'cfgPath');
-
-        $generatorXml.constructorArg(res, 2, secondFs, 'userName', null, true);
-
-        res.endBlock('</bean>');
-        res.endBlock('</property>');
-
-        res.needEmptyLine = true;
-    }
-
-    return res;
-};
-
-// Generate IGFS general configuration.
-$generatorXml.igfsGeneral = function(igfs, res) {
-    if (!res)
-        res = $generatorCommon.builder();
-
-    if ($generatorCommon.isDefinedAndNotEmpty(igfs.name)) {
-        igfs.dataCacheName = $generatorCommon.igfsDataCache(igfs).name;
-        igfs.metaCacheName = $generatorCommon.igfsMetaCache(igfs).name;
-
-        $generatorXml.property(res, igfs, 'name');
-        $generatorXml.property(res, igfs, 'dataCacheName');
-        $generatorXml.property(res, igfs, 'metaCacheName');
-        $generatorXml.property(res, igfs, 'defaultMode', null, 'DUAL_ASYNC');
-
-        res.needEmptyLine = true;
-    }
-
-    return res;
-};
-
-// Generate IGFS misc configuration.
-$generatorXml.igfsMisc = function(igfs, res) {
-    if (!res)
-        res = $generatorCommon.builder();
-
-    $generatorXml.property(res, igfs, 'blockSize', null, 65536);
-    $generatorXml.property(res, igfs, 'streamBufferSize', null, 65536);
-    $generatorXml.property(res, igfs, 'maxSpaceSize', null, 0);
-    $generatorXml.property(res, igfs, 'maximumTaskRangeLength', null, 0);
-    $generatorXml.property(res, igfs, 'managementPort', null, 11400);
-    $generatorXml.property(res, igfs, 'perNodeBatchSize', null, 100);
-    $generatorXml.property(res, igfs, 'perNodeParallelBatchCount', null, 8);
-    $generatorXml.property(res, igfs, 'prefetchBlocks', null, 0);
-    $generatorXml.property(res, igfs, 'sequentialReadsBeforePrefetch', null, 0);
-    $generatorXml.property(res, igfs, 'trashPurgeTimeout', null, 1000);
-    $generatorXml.property(res, igfs, 'colocateMetadata', null, true);
-    $generatorXml.property(res, igfs, 'relaxedConsistency', null, true);
-
-    res.softEmptyLine();
-
-    if (igfs.pathModes && igfs.pathModes.length > 0) {
-        res.startBlock('<property name="pathModes">');
-        res.startBlock('<map>');
-
-        _.forEach(igfs.pathModes, function(pair) {
-            res.line('<entry key="' + pair.path + '" value="' + pair.mode + '"/>');
-        });
-
-        res.endBlock('</map>');
-        res.endBlock('</property>');
-    }
-
-    return res;
-};
-
-// Generate DataSource beans.
-$generatorXml.generateDataSources = function(datasources, res) {
-    if (!res)
-        res = $generatorCommon.builder();
-
-    if (datasources.length > 0) {
-        res.line('<!-- Data source beans will be initialized from external properties file. -->');
-
-        _.forEach(datasources, function(item) {
-            const beanId = item.dataSourceBean;
-
-            res.startBlock('<bean id="' + beanId + '" class="' + item.className + '">');
-
-            switch (item.dialect) {
-                case 'Generic':
-                    res.line('<property name="jdbcUrl" value="${' + beanId + '.jdbc.url}"/>');
-
-                    break;
-
-                case 'DB2':
-                    res.line('<property name="serverName" value="${' + beanId + '.jdbc.server_name}"/>');
-                    res.line('<property name="portNumber" value="${' + beanId + '.jdbc.port_number}"/>');
-                    res.line('<property name="databaseName" value="${' + beanId + '.jdbc.database_name}"/>');
-                    res.line('<property name="driverType" value="${' + beanId + '.jdbc.driver_type}"/>');
-
-                    break;
-
-                case 'PostgreSQL':
-                    res.line('<property name="url" value="${' + beanId + '.jdbc.url}"/>');
-
-                    break;
-
-                default:
-                    res.line('<property name="URL" value="${' + beanId + '.jdbc.url}"/>');
-            }
-
-            res.line('<property name="user" value="${' + beanId + '.jdbc.username}"/>');
-            res.line('<property name="password" value="${' + beanId + '.jdbc.password}"/>');
-
-            res.endBlock('</bean>');
-
-            res.needEmptyLine = true;
-
-            res.emptyLineIfNeeded();
-        });
-
-        res.needEmptyLine = true;
-
-        res.emptyLineIfNeeded();
-    }
-
-    return res;
-};
-
-$generatorXml.clusterConfiguration = function(cluster, clientNearCfg, res) {
-    const isSrvCfg = _.isNil(clientNearCfg);
-
-    if (!isSrvCfg) {
-        res.line('<property name="clientMode" value="true"/>');
-
-        res.needEmptyLine = true;
-    }
-
-    $generatorXml.clusterGeneral(cluster, res);
-
-    $generatorXml.clusterAtomics(cluster.atomicConfiguration, res);
-
-    $generatorXml.clusterBinary(cluster.binaryConfiguration, res);
-
-    $generatorXml.clusterCollision(cluster.collision, res);
-
-    $generatorXml.clusterCommunication(cluster, res);
-
-    $generatorXml.clusterConnector(cluster.connector, res);
-
-    $generatorXml.clusterDeployment(cluster, res);
-
-    $generatorXml.clusterEvents(cluster, res);
-
-    $generatorXml.clusterFailover(cluster, res);
-
-    $generatorXml.clusterLogger(cluster.logger, res);
-
-    $generatorXml.clusterMarshaller(cluster, res);
-
-    $generatorXml.clusterMetrics(cluster, res);
-
-    $generatorXml.clusterSwap(cluster, res);
-
-    $generatorXml.clusterTime(cluster, res);
-
-    $generatorXml.clusterPools(cluster, res);
-
-    $generatorXml.clusterTransactions(cluster.transactionConfiguration, res);
-
-    $generatorXml.clusterCaches(cluster.caches, cluster.igfss, isSrvCfg, res);
-
-    $generatorXml.clusterSsl(cluster, res);
-
-    if (isSrvCfg)
-        $generatorXml.igfss(cluster.igfss, res);
-
-    $generatorXml.clusterUserAttributes(cluster, res);
-
-    return res;
-};
-
-$generatorXml.cluster = function(cluster, clientNearCfg) {
-    if (cluster) {
-        const res = $generatorCommon.builder(1);
-
-        if (clientNearCfg) {
-            res.startBlock('<bean id="nearCacheBean" class="org.apache.ignite.configuration.NearCacheConfiguration">');
-
-            if (clientNearCfg.nearStartSize)
-                $generatorXml.property(res, clientNearCfg, 'nearStartSize');
-
-            if (clientNearCfg.nearEvictionPolicy && clientNearCfg.nearEvictionPolicy.kind)
-                $generatorXml.evictionPolicy(res, clientNearCfg.nearEvictionPolicy, 'nearEvictionPolicy');
-
-            res.endBlock('</bean>');
-
-            res.needEmptyLine = true;
-
-            res.emptyLineIfNeeded();
-        }
-
-        // Generate Ignite Configuration.
-        res.startBlock('<bean class="org.apache.ignite.configuration.IgniteConfiguration">');
-
-        $generatorXml.clusterConfiguration(cluster, clientNearCfg, res);
-
-        res.endBlock('</bean>');
-
-        // Build final XML:
-        // 1. Add header.
-        let xml = '<?xml version="1.0" encoding="UTF-8"?>\n\n';
-
-        xml += '<!-- ' + $generatorCommon.mainComment() + ' -->\n\n';
-        xml += '<beans xmlns="http://www.springframework.org/schema/beans"\n';
-        xml += '       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"\n';
-        xml += '       xmlns:util="http://www.springframework.org/schema/util"\n';
-        xml += '       xsi:schemaLocation="http://www.springframework.org/schema/beans\n';
-        xml += '                           http://www.springframework.org/schema/beans/spring-beans.xsd\n';
-        xml += '                           http://www.springframework.org/schema/util\n';
-        xml += '                           http://www.springframework.org/schema/util/spring-util.xsd">\n';
-
-        // 2. Add external property file
-        if ($generatorCommon.secretPropertiesNeeded(cluster)) {
-            xml += '    <!-- Load external properties file. -->\n';
-            xml += '    <bean id="placeholderConfig" class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">\n';
-            xml += '        <property name="location" value="classpath:secret.properties"/>\n';
-            xml += '    </bean>\n\n';
-        }
-
-        // 3. Add data sources.
-        xml += $generatorXml.generateDataSources(res.datasources, $generatorCommon.builder(1)).asString();
-
-        // 3. Add main content.
-        xml += res.asString();
-
-        // 4. Add footer.
-        xml += '\n</beans>';
-
-        return xml;
-    }
-
-    return '';
-};
-
-export default $generatorXml;

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/src/main/js/gulpfile.babel.js/index.js
----------------------------------------------------------------------
diff --git a/modules/web-console/src/main/js/gulpfile.babel.js/index.js b/modules/web-console/src/main/js/gulpfile.babel.js/index.js
deleted file mode 100644
index 95602a1..0000000
--- a/modules/web-console/src/main/js/gulpfile.babel.js/index.js
+++ /dev/null
@@ -1,26 +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 gulp from 'gulp';
-import requireDir from 'require-dir';
-
-// Require all tasks in gulpfile.js/tasks, including subfolders.
-requireDir('./tasks', { recurse: true });
-
-// Default no-arg task.
-gulp.task('default', ['build']);
-

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/src/main/js/gulpfile.babel.js/paths.js
----------------------------------------------------------------------
diff --git a/modules/web-console/src/main/js/gulpfile.babel.js/paths.js b/modules/web-console/src/main/js/gulpfile.babel.js/paths.js
deleted file mode 100644
index cca3643..0000000
--- a/modules/web-console/src/main/js/gulpfile.babel.js/paths.js
+++ /dev/null
@@ -1,70 +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 path from 'path';
-
-const rootDir = path.resolve('./');
-const srcDir = path.resolve('app');
-const destDir = path.resolve('build');
-
-const igniteModulesDir = process.env.IGNITE_MODULES ? path.normalize(process.env.IGNITE_MODULES) : './ignite_modules';
-const igniteModulesTemp = path.resolve('ignite_modules_temp');
-
-const jadePaths = [
-    './views/*.jade',
-    './views/**/*.jade'
-];
-
-const resourcePaths = [
-    './public/**/*.png',
-    './public/*.ico'
-];
-
-const jadeModulePaths = [
-    igniteModulesDir + '/**/view/**/*.jade'
-];
-
-const appModulePaths = [
-    igniteModulesDir + '/index.js',
-    igniteModulesDir + '/**/main.js',
-    igniteModulesDir + '/**/module.js',
-    igniteModulesDir + '/**/app/modules/*.js',
-    igniteModulesDir + '/**/app/modules/**/*.js',
-    igniteModulesDir + '/**/app/modules/**/*.jade',
-    igniteModulesDir + '/**/app/**/*.css',
-    igniteModulesDir + '/**/app/data/*.json'
-];
-
-const resourceModulePaths = [
-    igniteModulesDir + '/**/images/*.png',
-    igniteModulesDir + '/*.ico'
-];
-
-export {
-    rootDir,
-    srcDir,
-    destDir,
-    igniteModulesDir,
-    igniteModulesTemp,
-
-    jadePaths,
-    resourcePaths,
-
-    jadeModulePaths,
-    resourceModulePaths,
-    appModulePaths
-};


[19/52] ignite git commit: Web Console beta-3.

Posted by ak...@apache.org.
http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/src/main/js/app/modules/form/field/form-control-feedback.directive.js
----------------------------------------------------------------------
diff --git a/modules/web-console/src/main/js/app/modules/form/field/form-control-feedback.directive.js b/modules/web-console/src/main/js/app/modules/form/field/form-control-feedback.directive.js
deleted file mode 100644
index 058bcc3..0000000
--- a/modules/web-console/src/main/js/app/modules/form/field/form-control-feedback.directive.js
+++ /dev/null
@@ -1,40 +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 ['formControlFeedback', [() => {
-    const link = ($scope, $element, $attrs, [form]) => {
-        let name = $scope.name;
-
-        if (_.isNil(name))
-            name = $attrs.name;
-
-        const err = $attrs.igniteError;
-        const msg = $attrs.igniteErrorMessage;
-
-        if (name && err && msg) {
-            form.$errorMessages = form.$errorMessages || {};
-            form.$errorMessages[name] = form.$errorMessages[name] || {};
-            form.$errorMessages[name][err] = msg;
-        }
-    };
-
-    return {
-        restrict: 'C',
-        link,
-        require: ['^form']
-    };
-}]];

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/src/main/js/app/modules/form/field/input/autofocus.directive.js
----------------------------------------------------------------------
diff --git a/modules/web-console/src/main/js/app/modules/form/field/input/autofocus.directive.js b/modules/web-console/src/main/js/app/modules/form/field/input/autofocus.directive.js
deleted file mode 100644
index c963cc1..0000000
--- a/modules/web-console/src/main/js/app/modules/form/field/input/autofocus.directive.js
+++ /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.
- */
-
-export default ['igniteFormFieldInputAutofocus', [() => {
-    const link = (scope, el, attrs) => {
-        if (_.isUndefined(attrs.igniteFormFieldInputAutofocus) || attrs.igniteFormFieldInputAutofocus !== 'true')
-            return;
-
-        el.focus();
-    };
-
-    return {
-        restrict: 'A',
-        link
-    };
-}]];

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/src/main/js/app/modules/form/field/input/checkbox.directive.js
----------------------------------------------------------------------
diff --git a/modules/web-console/src/main/js/app/modules/form/field/input/checkbox.directive.js b/modules/web-console/src/main/js/app/modules/form/field/input/checkbox.directive.js
deleted file mode 100644
index 3d84b4e..0000000
--- a/modules/web-console/src/main/js/app/modules/form/field/input/checkbox.directive.js
+++ /dev/null
@@ -1,66 +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 templateUrl from './checkbox.jade';
-
-export default ['igniteFormFieldInputCheckbox', ['IgniteFormGUID', 'IgniteLegacyTable', (guid, LegacyTable) => {
-    const link = (scope, el, attrs, [form, label]) => {
-        const {id, name} = scope;
-        const field = form[name];
-
-        scope.field = field;
-        label.for = scope.id = id || guid();
-
-        label.type = 'internal';
-
-        form.$defaults = form.$defaults || {};
-        form.$defaults[name] = _.cloneDeep(scope.value);
-
-        const setAsDefault = () => {
-            if (!form.$pristine) return;
-
-            form.$defaults = form.$defaults || {};
-            form.$defaults[name] = _.cloneDeep(scope.value);
-        };
-
-        scope.$watch(() => form.$pristine, setAsDefault);
-        scope.$watch('value', setAsDefault);
-
-        scope.tableReset = () => {
-            LegacyTable.tableSaveAndReset();
-        };
-    };
-
-    return {
-        restrict: 'E',
-        scope: {
-            id: '@',
-            name: '@',
-            required: '=ngRequired',
-            disabled: '=ngDisabled',
-
-            focus: '=ngFocus',
-
-            value: '=ngModel'
-        },
-        link,
-        templateUrl,
-        replace: true,
-        transclude: true,
-        require: ['^form', '?^igniteFormField']
-    };
-}]];

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/src/main/js/app/modules/form/field/input/checkbox.jade
----------------------------------------------------------------------
diff --git a/modules/web-console/src/main/js/app/modules/form/field/input/checkbox.jade b/modules/web-console/src/main/js/app/modules/form/field/input/checkbox.jade
deleted file mode 100644
index 477d4b2..0000000
--- a/modules/web-console/src/main/js/app/modules/form/field/input/checkbox.jade
+++ /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.
-
-.input-tip
-    input(
-        id='{{ id }}'
-        name='{{ name }}'
-        type='checkbox'
-
-        data-ng-model='value'
-        data-ng-required='required || false'
-        data-ng-disabled='disabled || false'
-
-        data-ng-focus='tableReset()'
-    )
-
-    span(ng-transclude='')

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/src/main/js/app/modules/form/field/input/datalist.directive.js
----------------------------------------------------------------------
diff --git a/modules/web-console/src/main/js/app/modules/form/field/input/datalist.directive.js b/modules/web-console/src/main/js/app/modules/form/field/input/datalist.directive.js
deleted file mode 100644
index 6c43a2a..0000000
--- a/modules/web-console/src/main/js/app/modules/form/field/input/datalist.directive.js
+++ /dev/null
@@ -1,122 +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 templateUrl from './datalist.jade';
-
-export default ['igniteFormFieldInputDatalist', ['IgniteFormGUID', 'IgniteLegacyTable', (guid, LegacyTable) => {
-    const link = (scope, element, attrs, [ngModel, form, label], transclude) => {
-        const {id, ngModelName} = scope;
-
-        const name = ngModelName;
-
-        scope.id = id || guid();
-        scope.form = form;
-        scope.name = ngModelName + 'TextInput';
-        scope.ngModel = ngModel;
-
-        Object.defineProperty(scope, 'field', {
-            get: () => scope.form[scope.name]
-        });
-
-        if (label) {
-            label.for = scope.id;
-
-            scope.label = label;
-
-            scope.$watch('required', (required) => {
-                label.required = required || false;
-            });
-        }
-
-        form.$defaults = form.$defaults || {};
-
-        if (form.$pristine) {
-            if (!(_.isNull(form.$defaults[name]) || _.isUndefined(form.$defaults[name]))) {
-                scope.value = form.$defaults[name];
-                ngModel.$setViewValue(scope.value);
-            } else
-                form.$defaults[name] = _.cloneDeep(scope.value);
-        }
-
-        const setAsDefault = () => {
-            if (!form.$pristine) return;
-
-            form.$defaults = form.$defaults || {};
-            form.$defaults[name] = _.cloneDeep(scope.value);
-        };
-
-        scope.$watch(() => form.$pristine, setAsDefault);
-        scope.$watch('value', setAsDefault);
-
-        const checkValid = () => {
-            const input = element.find('input');
-
-            const invalid = ngModel.$invalid || (input[0].required && !input[0].value);
-
-            input.removeClass(invalid ? 'ng-valid' : 'ng-invalid');
-            input.addClass(invalid ? 'ng-invalid' : 'ng-valid');
-        };
-
-        scope.ngChange = () => {
-            ngModel.$setViewValue(scope.value);
-
-            if (_.isEqual(scope.value, form.$defaults[name]))
-                ngModel.$setPristine();
-            else
-                ngModel.$setDirty();
-
-            setTimeout(checkValid, 100); // Use setTimeout() workaround of problem of two controllers.
-        };
-
-        ngModel.$render = () => {
-            scope.value = ngModel.$modelValue;
-        };
-
-        scope.tableReset = () => {
-            LegacyTable.tableSaveAndReset();
-        };
-
-        transclude(scope.$parent, function(clone, tscope) {
-            tscope.form = form;
-            tscope.ngModelName = ngModelName;
-
-            element.find('.transclude-here').append(clone);
-        });
-    };
-
-    return {
-        restrict: 'E',
-        scope: {
-            id: '@',
-            ngModelName: '@name',
-            placeholder: '@',
-            required: '=ngRequired',
-            disabled: '=ngDisabled',
-            ngBlur: '&',
-
-            options: '=',
-
-            focus: '=ngFocus',
-            autofocus: '=igniteFormFieldInputAutofocus'
-        },
-        link,
-        templateUrl,
-        replace: true,
-        transclude: true,
-        require: ['ngModel', '^form', '?^igniteFormField']
-    };
-}]];

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/src/main/js/app/modules/form/field/input/datalist.jade
----------------------------------------------------------------------
diff --git a/modules/web-console/src/main/js/app/modules/form/field/input/datalist.jade b/modules/web-console/src/main/js/app/modules/form/field/input/datalist.jade
deleted file mode 100644
index 7ae1411..0000000
--- a/modules/web-console/src/main/js/app/modules/form/field/input/datalist.jade
+++ /dev/null
@@ -1,51 +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.
-
-mixin feedback(isCheckPristine, error, errorMessage)
-    -var checkPristine = isCheckPristine ? '!field.$pristine && ' : ''
-
-    i.fa.fa-exclamation-triangle.form-control-feedback(
-        ng-if='#{checkPristine}field.$error.#{error}'
-        bs-tooltip='"#{errorMessage}"'
-        ignite-error=error
-        ignite-error-message=errorMessage
-    )
-
-.input-tip
-    input.form-control(
-        id='{{ id }}'
-        name='{{ name }}'
-        placeholder='{{ placeholder }}'
-
-        data-ng-model='value'
-
-        data-ng-blur='ngBlur()'
-        data-ng-change='ngChange()'
-        data-ng-required='required || false'
-        data-ng-disabled='disabled || false'
-
-        data-ignite-form-field-input-autofocus='{{autofocus}}'
-
-        bs-typeahead
-        bs-options='item for item in options'
-        container='body'
-        data-min-length='1'
-        ignite-retain-selection
-    )
-
-    +feedback(true, 'required', '{{ label.name }} could not be empty!')
-
-    span.transclude-here

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/src/main/js/app/modules/form/field/input/number.directive.js
----------------------------------------------------------------------
diff --git a/modules/web-console/src/main/js/app/modules/form/field/input/number.directive.js b/modules/web-console/src/main/js/app/modules/form/field/input/number.directive.js
deleted file mode 100644
index 0d21f5b..0000000
--- a/modules/web-console/src/main/js/app/modules/form/field/input/number.directive.js
+++ /dev/null
@@ -1,76 +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 templateUrl from './number.jade';
-
-export default ['igniteFormFieldInputNumber', ['IgniteFormGUID', 'IgniteLegacyTable', (guid, LegacyTable) => {
-    const link = (scope, el, attrs, [form, label]) => {
-        const {id, name} = scope;
-        const field = form[name];
-
-        scope.id = id || guid();
-        scope.field = field;
-
-        if (label) {
-            label.for = scope.id;
-
-            scope.$watch('required', (required) => {
-                label.required = required || false;
-            });
-        }
-
-        form.$defaults = form.$defaults || {};
-        form.$defaults[name] = _.cloneDeep(scope.value);
-
-        const setAsDefault = () => {
-            if (!form.$pristine) return;
-
-            form.$defaults = form.$defaults || {};
-            form.$defaults[name] = _.cloneDeep(scope.value);
-        };
-
-        scope.$watch(() => form.$pristine, setAsDefault);
-        scope.$watch('value', setAsDefault);
-
-        scope.tableReset = () => {
-            LegacyTable.tableSaveAndReset();
-        };
-    };
-
-    return {
-        restrict: 'E',
-        scope: {
-            id: '@',
-            name: '@',
-            placeholder: '@',
-            required: '=ngRequired',
-            disabled: '=ngDisabled',
-
-            focus: '=ngFocus',
-
-            min: '@',
-            max: '@',
-            step: '@',
-            value: '=ngModel'
-        },
-        link,
-        templateUrl,
-        replace: true,
-        transclude: true,
-        require: ['^form', '?^igniteFormField']
-    };
-}]];

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/src/main/js/app/modules/form/field/input/number.jade
----------------------------------------------------------------------
diff --git a/modules/web-console/src/main/js/app/modules/form/field/input/number.jade b/modules/web-console/src/main/js/app/modules/form/field/input/number.jade
deleted file mode 100644
index e72a1d0..0000000
--- a/modules/web-console/src/main/js/app/modules/form/field/input/number.jade
+++ /dev/null
@@ -1,50 +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.
-
-mixin feedback(isCheckPristine, error, errorMessage)
-    -var checkPristine = isCheckPristine ? '!field.$pristine && ' : ''
-
-    i.fa.fa-exclamation-triangle.form-control-feedback(
-        ng-if='#{checkPristine}field.$error.#{error}'
-        bs-tooltip='"#{errorMessage}"'
-        ignite-error=error
-        ignite-error-message=errorMessage
-    )
-
-.input-tip
-    input.form-control(
-        id='{{ id }}'
-        name='{{ name }}'
-        placeholder='{{ placeholder }}'
-        type='number'
-        min='{{ min || 0 }}'
-        max='{{ max || Number.MAX_VALUE }}'
-        step='{{ step || 1 }}'
-
-        data-ng-model='value'
-
-        data-ng-required='required || false'
-        data-ng-disabled='disabled || false'
-
-        data-ng-focus='tableReset()'
-    )
-
-    +feedback(true, 'required', 'This field could not be empty')
-    +feedback(false, 'min', 'Value is less than allowable minimum: {{ min || 0 }}')
-    +feedback(false, 'max', 'Value is more than allowable maximum: {{ max }}')
-    +feedback(false, 'number', 'Only numbers allowed')
-
-    span(ng-transclude='')

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/src/main/js/app/modules/form/field/input/text.css
----------------------------------------------------------------------
diff --git a/modules/web-console/src/main/js/app/modules/form/field/input/text.css b/modules/web-console/src/main/js/app/modules/form/field/input/text.css
deleted file mode 100644
index c76bebd..0000000
--- a/modules/web-console/src/main/js/app/modules/form/field/input/text.css
+++ /dev/null
@@ -1,41 +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.
- */
-
-.checkbox label .input-tip {
-	position: initial;
-}
-
-.input-tip .fa-floppy-o {
-	position: absolute;
-    top: 0;
-    right: 0;
-    z-index: 2;
-
-    width: 34px;
-    height: 34px;
-
-    text-align: center;
-
-    display: inline-block;
-    line-height: 28px;
-    pointer-events: initial;
-}
-
-.input-tip .form-control-feedback {
-    height: auto;
-}
-

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/src/main/js/app/modules/form/field/input/text.directive.js
----------------------------------------------------------------------
diff --git a/modules/web-console/src/main/js/app/modules/form/field/input/text.directive.js b/modules/web-console/src/main/js/app/modules/form/field/input/text.directive.js
deleted file mode 100644
index 56c02b5..0000000
--- a/modules/web-console/src/main/js/app/modules/form/field/input/text.directive.js
+++ /dev/null
@@ -1,126 +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 templateUrl from './text.jade';
-import './text.css';
-
-export default ['igniteFormFieldInputText', ['IgniteFormGUID', 'IgniteLegacyTable', (guid, LegacyTable) => {
-    const link = (scope, element, attrs, [ngModel, form, label], transclude) => {
-        const {id, ngModelName} = scope;
-
-        const name = ngModelName;
-
-        scope.id = id || guid();
-        scope.form = form;
-        scope.name = ngModelName + 'TextInput';
-        scope.ngModel = ngModel;
-
-        Object.defineProperty(scope, 'field', {
-            get: () => scope.form[scope.name]
-        });
-
-        if (label) {
-            label.for = scope.id;
-
-            scope.label = label;
-            scope.labelName = label.name;
-
-            scope.$watch('required', (required) => {
-                label.required = required || false;
-            });
-        }
-        else
-            scope.labelName = attrs.igniteLabelName || 'Value';
-
-        form.$defaults = form.$defaults || {};
-
-        if (form.$pristine) {
-            if (!(_.isNull(form.$defaults[name]) || _.isUndefined(form.$defaults[name]))) {
-                scope.value = form.$defaults[name];
-                ngModel.$setViewValue(scope.value);
-            } else
-                form.$defaults[name] = _.cloneDeep(scope.value);
-        }
-
-        const setAsDefault = () => {
-            if (!form.$pristine) return;
-
-            form.$defaults = form.$defaults || {};
-            form.$defaults[name] = _.cloneDeep(scope.value);
-        };
-
-        scope.$watch(() => form.$pristine, setAsDefault);
-        scope.$watch('value', setAsDefault);
-
-        const checkValid = () => {
-            const input = element.find('input');
-
-            const invalid = ngModel.$invalid || (input[0].required && !input[0].value);
-
-            input.removeClass(invalid ? 'ng-valid' : 'ng-invalid');
-            input.addClass(invalid ? 'ng-invalid' : 'ng-valid');
-        };
-
-        scope.ngChange = () => {
-            ngModel.$setViewValue(scope.value);
-
-            if (_.isEqual(scope.value, form.$defaults[name]))
-                ngModel.$setPristine();
-            else
-                ngModel.$setDirty();
-
-            setTimeout(checkValid, 100); // Use setTimeout() workaround of problem of two controllers.
-        };
-
-        ngModel.$render = () => {
-            scope.value = ngModel.$modelValue;
-        };
-
-        scope.tableReset = () => {
-            LegacyTable.tableSaveAndReset();
-        };
-
-        transclude(scope.$parent, function(clone, tscope) {
-            tscope.form = form;
-            tscope.ngModelName = ngModelName;
-
-            element.find('.transclude-here').append(clone);
-        });
-    };
-
-    return {
-        restrict: 'E',
-        scope: {
-            id: '@',
-            ngModelName: '@name',
-            placeholder: '@',
-            required: '=ngRequired',
-            disabled: '=ngDisabled',
-
-            focus: '=ngFocus',
-
-            ngBlur: '&',
-
-            autofocus: '=igniteFormFieldInputAutofocus'
-        },
-        link,
-        templateUrl,
-        replace: true,
-        transclude: true,
-        require: ['ngModel', '^form', '?^igniteFormField']
-    };
-}]];

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/src/main/js/app/modules/form/field/input/text.jade
----------------------------------------------------------------------
diff --git a/modules/web-console/src/main/js/app/modules/form/field/input/text.jade b/modules/web-console/src/main/js/app/modules/form/field/input/text.jade
deleted file mode 100644
index 8a1dfc2..0000000
--- a/modules/web-console/src/main/js/app/modules/form/field/input/text.jade
+++ /dev/null
@@ -1,48 +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.
-
-mixin feedback(isCheckPristine, error, errorMessage)
-    -var checkPristine = isCheckPristine ? '!field.$pristine && ' : ''
-
-    i.fa.fa-exclamation-triangle.form-control-feedback(
-        ng-if='#{checkPristine}field.$error.#{error}'
-        bs-tooltip='"#{errorMessage}"'
-        ignite-error=error
-        ignite-error-message=errorMessage
-    )
-
-.input-tip
-    input.form-control(
-        id='{{ id }}'
-        name='{{ name }}'
-        placeholder='{{ placeholder }}'
-        type='text'
-
-        data-ng-model='value'
-
-        data-ng-blur='ngBlur()'
-        data-ng-change='ngChange()'
-        data-ng-required='required || false'
-        data-ng-disabled='disabled || false'
-
-        data-ignite-form-field-input-autofocus='{{autofocus}}'
-
-        data-ng-focus='tableReset()'
-    )
-
-    +feedback(true, 'required', '{{ labelName }} could not be empty!')
-
-    span.transclude-here

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/src/main/js/app/modules/form/field/label.directive.js
----------------------------------------------------------------------
diff --git a/modules/web-console/src/main/js/app/modules/form/field/label.directive.js b/modules/web-console/src/main/js/app/modules/form/field/label.directive.js
deleted file mode 100644
index 9b812d7..0000000
--- a/modules/web-console/src/main/js/app/modules/form/field/label.directive.js
+++ /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.
- */
-
-export default ['igniteFormFieldLabel', [() => {
-    return {
-        restrict: 'E',
-        compile() {
-            return {
-                post($scope, $element, $attrs, [form, field], $transclude) {
-                    $transclude($scope, function(clone) {
-                        const text = clone.text();
-
-                        if (/(.*):$/.test(text))
-                            field.name = /(.*):$/.exec(text)[1];
-
-                        const $label = $element.parent().parent().find('label');
-
-                        if ($element[0].id) {
-                            const id = $element[0].id;
-
-                            $label[0].id = id.indexOf('+') >= 0 ? $scope.$eval(id) : id;
-                        }
-
-                        $label.append(clone);
-                    });
-                }
-            };
-        },
-        replace: true,
-        transclude: true,
-        require: ['^form', '?^igniteFormField']
-    };
-}]];

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/src/main/js/app/modules/form/field/tooltip.directive.js
----------------------------------------------------------------------
diff --git a/modules/web-console/src/main/js/app/modules/form/field/tooltip.directive.js b/modules/web-console/src/main/js/app/modules/form/field/tooltip.directive.js
deleted file mode 100644
index 5005280..0000000
--- a/modules/web-console/src/main/js/app/modules/form/field/tooltip.directive.js
+++ /dev/null
@@ -1,49 +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.
- */
-
-const template = '<i class="tipField fa fa-question-circle"></i>';
-
-export default ['igniteFormFieldTooltip', ['$tooltip', ($tooltip) => {
-    const link = ($scope, $element, $attrs, [form, field], $transclude) => {
-        const content = Array.prototype.slice
-            .apply($transclude($scope))
-            .reduce((html, el) => html += el.outerHTML || el.textContent || el, '');
-
-        $tooltip($element, { title: content });
-
-        if (field)
-            $element.attr('id', field.for + 'Tooltip');
-
-        // TODO cleanup css styles.
-        if ($element.hasClass('tipLabel'))
-            $element.removeClass('tipField');
-
-        if ($element.parent('label').length)
-            $element.addClass('tipLabel').removeClass('tipField');
-    };
-
-    return {
-        priority: 1,
-        restrict: 'E',
-        scope: {},
-        template,
-        link,
-        replace: true,
-        transclude: true,
-        require: ['^form', '?^igniteFormField']
-    };
-}]];

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/src/main/js/app/modules/form/field/up.directive.js
----------------------------------------------------------------------
diff --git a/modules/web-console/src/main/js/app/modules/form/field/up.directive.js b/modules/web-console/src/main/js/app/modules/form/field/up.directive.js
deleted file mode 100644
index d31bdc5..0000000
--- a/modules/web-console/src/main/js/app/modules/form/field/up.directive.js
+++ /dev/null
@@ -1,44 +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.
- */
-
-const template = '<i class="tipField fa fa-arrow-up ng-scope" ng-click="up()"></i>';
-
-export default ['igniteFormFieldUp', ['$tooltip', ($tooltip) => {
-    const link = (scope, $element) => {
-        $tooltip($element, { title: 'Move item up' });
-
-        scope.up = () => {
-            const idx = scope.models.indexOf(scope.model);
-
-            scope.models.splice(idx, 1);
-            scope.models.splice(idx - 1, 0, scope.model);
-        };
-    };
-
-    return {
-        restrict: 'E',
-        scope: {
-            model: '=ngModel',
-            models: '=models'
-        },
-        template,
-        link,
-        replace: true,
-        transclude: true,
-        require: '^form'
-    };
-}]];

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/src/main/js/app/modules/form/form.module.js
----------------------------------------------------------------------
diff --git a/modules/web-console/src/main/js/app/modules/form/form.module.js b/modules/web-console/src/main/js/app/modules/form/form.module.js
deleted file mode 100644
index 57a92fa..0000000
--- a/modules/web-console/src/main/js/app/modules/form/form.module.js
+++ /dev/null
@@ -1,101 +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 angular from 'angular';
-
-// Panel.
-import igniteFormPanel from './panel/panel.directive';
-import igniteFormPanelChevron from './panel/chevron.directive';
-import igniteFormRevert from './panel/revert.directive';
-
-// Field.
-import igniteFormField from './field/field.directive';
-import igniteFormFieldLabel from './field/label.directive';
-import igniteFormFieldTooltip from './field/tooltip.directive';
-import igniteFormFieldDropdown from './field/dropdown.directive';
-import igniteFormFieldInputNumber from './field/input/number.directive';
-import igniteFormFieldInputText from './field/input/text.directive';
-import igniteFormFieldInputCheckbox from './field/input/checkbox.directive';
-import igniteFormFieldInputDatalist from './field/input/datalist.directive';
-
-import placeholder from './field/bs-select-placeholder.directive';
-
-// Group.
-import igniteFormGroup from './group/group.directive';
-import igniteFormGroupAdd from './group/add.directive';
-import igniteFormGroupTooltip from './group/tooltip.directive';
-
-// Validators.
-import ipaddress from './validator/ipaddress.directive';
-import javaKeywords from './validator/java-keywords.directive';
-import javaPackageSpecified from './validator/java-package-specified.directive';
-import javaBuiltInClass from './validator/java-built-in-class.directive';
-import javaIdentifier from './validator/java-identifier.directive';
-import javaPackageName from './validator/java-package-name.directive';
-import propertyValueSpecified from './validator/property-value-specified.directive';
-import propertyUnique from './validator/property-unique.directive';
-import unique from './validator/unique.directive';
-
-// Helpers.
-import igniteFormFieldInputAutofocus from './field/input/autofocus.directive';
-import igniteFormFieldUp from './field/up.directive';
-import igniteFormFieldDown from './field/down.directive';
-import igniteFormControlFeedback from './field/form-control-feedback.directive';
-
-angular
-.module('ignite-console.Form', [
-
-])
-// Panel.
-.directive(...igniteFormPanel)
-.directive(...igniteFormPanelChevron)
-.directive(...igniteFormRevert)
-// Field.
-.directive(...igniteFormField)
-.directive(...igniteFormFieldLabel)
-.directive(...igniteFormFieldTooltip)
-.directive(...igniteFormFieldDropdown)
-.directive(...igniteFormFieldInputNumber)
-.directive(...igniteFormFieldInputText)
-.directive(...igniteFormFieldInputCheckbox)
-.directive(...igniteFormFieldInputDatalist)
-.directive(...placeholder)
-// Group.
-.directive(...igniteFormGroup)
-.directive(...igniteFormGroupAdd)
-.directive(...igniteFormGroupTooltip)
-// Validators.
-.directive(...ipaddress)
-.directive(...javaKeywords)
-.directive(...javaPackageSpecified)
-.directive(...javaBuiltInClass)
-.directive(...javaIdentifier)
-.directive(...javaPackageName)
-.directive(...propertyValueSpecified)
-.directive(...propertyUnique)
-.directive(...unique)
-// Helpers.
-.directive(...igniteFormFieldInputAutofocus)
-.directive(...igniteFormFieldUp)
-.directive(...igniteFormFieldDown)
-.directive(...igniteFormControlFeedback)
-// Generator of globally unique identifier.
-.factory('IgniteFormGUID', [() => {
-    let guid = 0;
-
-    return () => `form-field-${guid++}`;
-}]);

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/src/main/js/app/modules/form/group/add.directive.js
----------------------------------------------------------------------
diff --git a/modules/web-console/src/main/js/app/modules/form/group/add.directive.js b/modules/web-console/src/main/js/app/modules/form/group/add.directive.js
deleted file mode 100644
index 98560b5..0000000
--- a/modules/web-console/src/main/js/app/modules/form/group/add.directive.js
+++ /dev/null
@@ -1,40 +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.
- */
-
-const template = '<i class="group-legend-btn fa fa-plus"></i>';
-
-export default ['igniteFormGroupAdd', ['$tooltip', ($tooltip) => {
-    const link = ($scope, $element, $attrs, $ctrls, $transclude) => {
-        const content = Array.prototype.slice
-            .apply($transclude($scope))
-            .reduce((html, el) => html += el.outerHTML || el.textContent || el, '');
-
-        $tooltip($element, { title: content });
-
-        $element.closest('.group').find('.group-legend').append($element);
-    };
-
-    return {
-        restrict: 'E',
-        scope: {},
-        template,
-        link,
-        replace: true,
-        transclude: true,
-        require: ['^form', '^igniteFormGroup']
-    };
-}]];

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/src/main/js/app/modules/form/group/group.directive.js
----------------------------------------------------------------------
diff --git a/modules/web-console/src/main/js/app/modules/form/group/group.directive.js b/modules/web-console/src/main/js/app/modules/form/group/group.directive.js
deleted file mode 100644
index 20cad22..0000000
--- a/modules/web-console/src/main/js/app/modules/form/group/group.directive.js
+++ /dev/null
@@ -1,81 +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 templateUrl from './group.jade';
-
-export default ['igniteFormGroup', [() => {
-    const controller = [function() { }];
-
-    const link = (scope, el, attrs, [ngModelCtrl, ownFormCtrl, parentFormCtrl]) => {
-        if (!ownFormCtrl)
-            return;
-
-        const name = attrs.ngForm;
-        ngModelCtrl.$name = name;
-
-        parentFormCtrl.$addControl(ngModelCtrl);
-        parentFormCtrl.$removeControl(ownFormCtrl);
-
-        scope.ngModel = scope.ngModel || [];
-        parentFormCtrl.$defaults = parentFormCtrl.$defaults || {};
-
-        if (parentFormCtrl.$pristine) {
-            if (!(_.isNull(parentFormCtrl.$defaults[name]) || _.isUndefined(parentFormCtrl.$defaults[name])))
-                scope.ngModel = parentFormCtrl.$defaults[name];
-            else
-                parentFormCtrl.$defaults[name] = _.cloneDeep(scope.ngModel);
-        }
-
-        const setAsDefault = () => {
-            if (!parentFormCtrl.$pristine)
-                return;
-
-            scope.ngModel = scope.ngModel || [];
-            parentFormCtrl.$defaults = parentFormCtrl.$defaults || {};
-            parentFormCtrl.$defaults[name] = _.cloneDeep(scope.ngModel);
-        };
-
-        const setAsDirty = () => {
-            if (_.isEqual(scope.ngModel, parentFormCtrl.$defaults[name]))
-                ngModelCtrl.$setPristine();
-            else
-                ngModelCtrl.$setDirty();
-        };
-
-        scope.$watch(() => parentFormCtrl.$pristine, setAsDefault);
-
-        scope.$watch('ngModel', setAsDefault);
-        scope.$watch('ngModel', setAsDirty, true);
-    };
-
-    return {
-        restrict: 'E',
-        scope: {
-            ngModel: '=ngModel'
-        },
-        bindToController: {
-            label: '@'
-        },
-        link,
-        templateUrl,
-        controller,
-        controllerAs: 'group',
-        replace: true,
-        transclude: true,
-        require: ['?ngModel', '?form', '^^form']
-    };
-}]];

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/src/main/js/app/modules/form/group/group.jade
----------------------------------------------------------------------
diff --git a/modules/web-console/src/main/js/app/modules/form/group/group.jade b/modules/web-console/src/main/js/app/modules/form/group/group.jade
deleted file mode 100644
index ba3a8f2..0000000
--- a/modules/web-console/src/main/js/app/modules/form/group/group.jade
+++ /dev/null
@@ -1,21 +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.
-
-.group-section
-    .group
-        .group-legend
-            label {{::group.label}}
-        div(ng-transclude='')

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/src/main/js/app/modules/form/group/table.directive.js
----------------------------------------------------------------------
diff --git a/modules/web-console/src/main/js/app/modules/form/group/table.directive.js b/modules/web-console/src/main/js/app/modules/form/group/table.directive.js
deleted file mode 100644
index 8c4d0ed..0000000
--- a/modules/web-console/src/main/js/app/modules/form/group/table.directive.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 templateUrl from './table.jade';
-
-export default ['igniteFormGroupTable', [() => {
-    return {
-        restrict: 'E',
-        scope: {},
-        templateUrl,
-        replace: true,
-        transclude: true,
-        require: ['^form', '^igniteFormGroup']
-    };
-}]];

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/src/main/js/app/modules/form/group/table.jade
----------------------------------------------------------------------
diff --git a/modules/web-console/src/main/js/app/modules/form/group/table.jade b/modules/web-console/src/main/js/app/modules/form/group/table.jade
deleted file mode 100644
index 6f9486d..0000000
--- a/modules/web-console/src/main/js/app/modules/form/group/table.jade
+++ /dev/null
@@ -1,17 +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.
-
-div
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/src/main/js/app/modules/form/group/tooltip.directive.js
----------------------------------------------------------------------
diff --git a/modules/web-console/src/main/js/app/modules/form/group/tooltip.directive.js b/modules/web-console/src/main/js/app/modules/form/group/tooltip.directive.js
deleted file mode 100644
index 2202e7b..0000000
--- a/modules/web-console/src/main/js/app/modules/form/group/tooltip.directive.js
+++ /dev/null
@@ -1,40 +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.
- */
-
-const template = '<i class="group-legend-btn fa fa-question-circle"></i>';
-
-export default ['igniteFormGroupTooltip', ['$tooltip', ($tooltip) => {
-    const link = ($scope, $element, $attrs, $ctrls, $transclude) => {
-        const content = Array.prototype.slice
-            .apply($transclude($scope))
-            .reduce((html, el) => html += el.outerHTML || el.textContent || el, '');
-
-        $tooltip($element, { title: content });
-
-        $element.closest('.group').find('.group-legend').append($element);
-    };
-
-    return {
-        restrict: 'E',
-        scope: {},
-        template,
-        link,
-        replace: true,
-        transclude: true,
-        require: ['^form', '^igniteFormGroup']
-    };
-}]];

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/src/main/js/app/modules/form/panel/chevron.directive.js
----------------------------------------------------------------------
diff --git a/modules/web-console/src/main/js/app/modules/form/panel/chevron.directive.js b/modules/web-console/src/main/js/app/modules/form/panel/chevron.directive.js
deleted file mode 100644
index 6af560b..0000000
--- a/modules/web-console/src/main/js/app/modules/form/panel/chevron.directive.js
+++ /dev/null
@@ -1,53 +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.
- */
-
-const template = `<i class='fa' ng-class='isOpen ? "fa-chevron-circle-down" : "fa-chevron-circle-right"'></i>`; // eslint-disable-line quotes
-
-export default ['igniteFormPanelChevron', [() => {
-    const controller = [() => {}];
-
-    const link = ($scope, $element, $attrs, [bsCollapseCtrl]) => {
-        const $target = $element.parent().parent().find('.panel-collapse');
-
-        bsCollapseCtrl.$viewChangeListeners.push(function() {
-            const index = bsCollapseCtrl.$targets.reduce((acc, el, i) => {
-                if (el[0] === $target[0])
-                    acc.push(i);
-
-                return acc;
-            }, [])[0];
-
-            $scope.isOpen = false;
-
-            const active = bsCollapseCtrl.$activeIndexes();
-
-            if ((active instanceof Array) && active.indexOf(index) !== -1 || active === index)
-                $scope.isOpen = true;
-        });
-    };
-
-    return {
-        restrict: 'E',
-        scope: {},
-        link,
-        template,
-        controller,
-        replace: true,
-        transclude: true,
-        require: ['^bsCollapse']
-    };
-}]];

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/src/main/js/app/modules/form/panel/panel.directive.js
----------------------------------------------------------------------
diff --git a/modules/web-console/src/main/js/app/modules/form/panel/panel.directive.js b/modules/web-console/src/main/js/app/modules/form/panel/panel.directive.js
deleted file mode 100644
index b8e7c25..0000000
--- a/modules/web-console/src/main/js/app/modules/form/panel/panel.directive.js
+++ /dev/null
@@ -1,37 +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 ['form', [() => {
-    const link = (scope, $element, $attrs, [form]) => {
-        const $form = $element.parent().closest('form');
-
-        scope.$watch(() => {
-            return $form.hasClass('ng-pristine');
-        }, (value) => {
-            if (!value)
-                return;
-
-            form.$setPristine();
-        });
-    };
-
-    return {
-        restrict: 'E',
-        link,
-        require: ['^form']
-    };
-}]];

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/src/main/js/app/modules/form/panel/revert.directive.js
----------------------------------------------------------------------
diff --git a/modules/web-console/src/main/js/app/modules/form/panel/revert.directive.js b/modules/web-console/src/main/js/app/modules/form/panel/revert.directive.js
deleted file mode 100644
index d60efb8..0000000
--- a/modules/web-console/src/main/js/app/modules/form/panel/revert.directive.js
+++ /dev/null
@@ -1,53 +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.
- */
-
-const template = '<i ng-show="form.$dirty" class="fa fa-undo pull-right" ng-click="revert($event)"></i>';
-
-export default ['igniteFormRevert', ['$tooltip', 'IgniteLegacyTable', ($tooltip, LegacyTable) => {
-    const link = (scope, $element, $attrs, [form]) => {
-        $tooltip($element, { title: 'Undo unsaved changes' });
-
-        scope.form = form;
-
-        scope.revert = (e) => {
-            e.stopPropagation();
-
-            LegacyTable.tableReset();
-
-            _.forOwn(form.$defaults, (value, name) => {
-                const field = form[name];
-
-                if (field) {
-                    field.$setViewValue(value);
-                    field.$setPristine();
-                    field.$render();
-                }
-            });
-
-            form.$setPristine();
-        };
-    };
-
-    return {
-        restrict: 'E',
-        scope: { },
-        template,
-        link,
-        replace: true,
-        require: ['^form']
-    };
-}]];

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/src/main/js/app/modules/form/validator/ipaddress.directive.js
----------------------------------------------------------------------
diff --git a/modules/web-console/src/main/js/app/modules/form/validator/ipaddress.directive.js b/modules/web-console/src/main/js/app/modules/form/validator/ipaddress.directive.js
deleted file mode 100644
index 2ddc786..0000000
--- a/modules/web-console/src/main/js/app/modules/form/validator/ipaddress.directive.js
+++ /dev/null
@@ -1,86 +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 ['ipaddress', ['IgniteInetAddress', (InetAddress) => {
-    const onlyDigits = (str) => (/^\d+$/.test(str));
-
-    const strictParseInt = (str) => onlyDigits(str) ? parseInt(str, 10) : Number.NaN;
-
-    const parse = (commonIpAddress) => {
-        const [ipOrHost, portRange] = commonIpAddress.split(':');
-        const ports = _.isUndefined(portRange) ? [] : portRange.split('..').map(strictParseInt);
-
-        return {ipOrHost, ports};
-    };
-
-    const link = (scope, el, attrs, [ngModel]) => {
-        const isEmpty = (modelValue) => {
-            return ngModel.$isEmpty(modelValue) || _.isUndefined(attrs.ipaddress) || attrs.ipaddress !== 'true';
-        };
-
-        const portRange = !_.isNil(attrs.ipaddressWithPortRange);
-
-        if (attrs.ipaddressWithPort) {
-            ngModel.$validators.ipaddressPort = (modelValue, viewValue) => {
-                if (isEmpty(modelValue) || viewValue.indexOf(':') === -1)
-                    return true;
-
-                if ((viewValue.match(/:/g) || []).length > 1)
-                    return false;
-
-                const {ports} = parse(viewValue);
-
-                if (ports.length !== 1)
-                    return portRange;
-
-                return InetAddress.validPort(ports[0]);
-            };
-        }
-
-        if (portRange) {
-            ngModel.$validators.ipaddressPortRange = (modelValue, viewValue) => {
-                if (isEmpty(modelValue) || viewValue.indexOf('..') === -1)
-                    return true;
-
-                const {ports} = parse(viewValue);
-
-                if (ports.length !== 2)
-                    return false;
-
-                return InetAddress.validPort(ports[0]) && InetAddress.validPort(ports[1]) && ports[0] < ports[1];
-            };
-        }
-
-        ngModel.$validators.ipaddress = (modelValue, viewValue) => {
-            if (isEmpty(modelValue))
-                return true;
-
-            const {ipOrHost, ports} = parse(viewValue);
-
-            if (attrs.ipaddressWithPort || attrs.ipaddressWithPortRange || ports.length === 0)
-                return InetAddress.validHost(ipOrHost);
-
-            return false;
-        };
-    };
-
-    return {
-        restrict: 'A',
-        link,
-        require: ['ngModel']
-    };
-}]];

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/src/main/js/app/modules/form/validator/java-built-in-class.directive.js
----------------------------------------------------------------------
diff --git a/modules/web-console/src/main/js/app/modules/form/validator/java-built-in-class.directive.js b/modules/web-console/src/main/js/app/modules/form/validator/java-built-in-class.directive.js
deleted file mode 100644
index 1a4b504..0000000
--- a/modules/web-console/src/main/js/app/modules/form/validator/java-built-in-class.directive.js
+++ /dev/null
@@ -1,31 +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 ['javaBuiltInClass', ['JavaTypes', (JavaTypes) => {
-    const link = (scope, el, attrs, [ngModel]) => {
-        if (_.isUndefined(attrs.javaBuiltInClass) || !attrs.javaBuiltInClass)
-            return;
-
-        ngModel.$validators.javaBuiltInClass = (value) => JavaTypes.nonBuiltInClass(value);
-    };
-
-    return {
-        restrict: 'A',
-        link,
-        require: ['ngModel']
-    };
-}]];

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/src/main/js/app/modules/form/validator/java-identifier.directive.js
----------------------------------------------------------------------
diff --git a/modules/web-console/src/main/js/app/modules/form/validator/java-identifier.directive.js b/modules/web-console/src/main/js/app/modules/form/validator/java-identifier.directive.js
deleted file mode 100644
index 5cbf7fb..0000000
--- a/modules/web-console/src/main/js/app/modules/form/validator/java-identifier.directive.js
+++ /dev/null
@@ -1,31 +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 ['javaIdentifier', ['JavaTypes', (JavaTypes) => {
-    const link = (scope, el, attrs, [ngModel]) => {
-        if (_.isUndefined(attrs.javaIdentifier) || !attrs.javaIdentifier)
-            return;
-
-        ngModel.$validators.javaIdentifier = (value) => JavaTypes.validIdentifier(value);
-    };
-
-    return {
-        restrict: 'A',
-        link,
-        require: ['ngModel']
-    };
-}]];

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/src/main/js/app/modules/form/validator/java-keywords.directive.js
----------------------------------------------------------------------
diff --git a/modules/web-console/src/main/js/app/modules/form/validator/java-keywords.directive.js b/modules/web-console/src/main/js/app/modules/form/validator/java-keywords.directive.js
deleted file mode 100644
index d97e59a..0000000
--- a/modules/web-console/src/main/js/app/modules/form/validator/java-keywords.directive.js
+++ /dev/null
@@ -1,42 +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 ['javaKeywords', ['JavaTypes', (JavaTypes) => {
-    const link = (scope, el, attrs, [ngModel]) => {
-        if (_.isUndefined(attrs.javaKeywords) || !attrs.javaKeywords)
-            return;
-
-        const packageOnly = attrs.javaPackageName === 'package-only';
-
-        ngModel.$validators.javaKeywords = (value) => {
-            if (value) {
-                if (!JavaTypes.validIdentifier(value) || (!packageOnly && !JavaTypes.packageSpecified(value)))
-                    return true;
-
-                return _.findIndex(value.split('.'), JavaTypes.isKeywords) < 0;
-            }
-
-            return true;
-        };
-    };
-
-    return {
-        restrict: 'A',
-        link,
-        require: ['ngModel']
-    };
-}]];

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/src/main/js/app/modules/form/validator/java-package-name.directive.js
----------------------------------------------------------------------
diff --git a/modules/web-console/src/main/js/app/modules/form/validator/java-package-name.directive.js b/modules/web-console/src/main/js/app/modules/form/validator/java-package-name.directive.js
deleted file mode 100644
index ac38179..0000000
--- a/modules/web-console/src/main/js/app/modules/form/validator/java-package-name.directive.js
+++ /dev/null
@@ -1,31 +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 ['javaPackageName', ['JavaTypes', (JavaTypes) => {
-    const link = (scope, el, attrs, [ngModel]) => {
-        if (_.isUndefined(attrs.javaPackageName) || !attrs.javaPackageName)
-            return;
-
-        ngModel.$validators.javaPackageName = (value) => JavaTypes.validPackage(value);
-    };
-
-    return {
-        restrict: 'A',
-        link,
-        require: ['ngModel']
-    };
-}]];

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/src/main/js/app/modules/form/validator/java-package-specified.directive.js
----------------------------------------------------------------------
diff --git a/modules/web-console/src/main/js/app/modules/form/validator/java-package-specified.directive.js b/modules/web-console/src/main/js/app/modules/form/validator/java-package-specified.directive.js
deleted file mode 100644
index 451d7ec..0000000
--- a/modules/web-console/src/main/js/app/modules/form/validator/java-package-specified.directive.js
+++ /dev/null
@@ -1,34 +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 ['javaPackageSpecified', ['JavaTypes', (JavaTypes) => {
-    const link = (scope, el, attrs, [ngModel]) => {
-        if (_.isUndefined(attrs.javaPackageSpecified))
-            return;
-
-        const allowBuiltIn = attrs.javaPackageSpecified === 'allow-built-in';
-
-        ngModel.$validators.javaPackageSpecified = (value) => !value || !JavaTypes.validIdentifier(value) || JavaTypes.packageSpecified(value) ||
-                (allowBuiltIn && !JavaTypes.nonBuiltInClass(value));
-    };
-
-    return {
-        restrict: 'A',
-        link,
-        require: ['ngModel']
-    };
-}]];

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/src/main/js/app/modules/form/validator/property-unique.directive.js
----------------------------------------------------------------------
diff --git a/modules/web-console/src/main/js/app/modules/form/validator/property-unique.directive.js b/modules/web-console/src/main/js/app/modules/form/validator/property-unique.directive.js
deleted file mode 100644
index 8cfae89..0000000
--- a/modules/web-console/src/main/js/app/modules/form/validator/property-unique.directive.js
+++ /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.
- */
-
-export default ['ignitePropertyUnique', ['$parse', ($parse) => {
-    const link = (scope, el, attrs, [ngModel]) => {
-        if (_.isUndefined(attrs.ignitePropertyUnique) || !attrs.ignitePropertyUnique)
-            return;
-
-        ngModel.$validators.ignitePropertyUnique = (value) => {
-            const arr = $parse(attrs.ignitePropertyUnique)(scope);
-
-            // Return true in case if array not exist, array empty.
-            if (!value || !arr || !arr.length)
-                return true;
-
-            const key = value.split('=')[0];
-            const idx = _.findIndex(arr, (item) => item.split('=')[0] === key);
-
-            // In case of new element check all items.
-            if (attrs.name === 'new')
-                return idx < 0;
-
-            // Check for $index in case of editing in-place.
-            return (_.isNumber(scope.$index) && (idx < 0 || scope.$index === idx));
-        };
-    };
-
-    return {
-        restrict: 'A',
-        link,
-        require: ['ngModel']
-    };
-}]];

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/src/main/js/app/modules/form/validator/property-value-specified.directive.js
----------------------------------------------------------------------
diff --git a/modules/web-console/src/main/js/app/modules/form/validator/property-value-specified.directive.js b/modules/web-console/src/main/js/app/modules/form/validator/property-value-specified.directive.js
deleted file mode 100644
index d113a4f..0000000
--- a/modules/web-console/src/main/js/app/modules/form/validator/property-value-specified.directive.js
+++ /dev/null
@@ -1,31 +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 ['ignitePropertyValueSpecified', [() => {
-    const link = (scope, el, attrs, [ngModel]) => {
-        if (_.isUndefined(attrs.ignitePropertyValueSpecified) || !attrs.ignitePropertyValueSpecified)
-            return;
-
-        ngModel.$validators.ignitePropertyValueSpecified = (value) => value ? value.indexOf('=') > 0 : true;
-    };
-
-    return {
-        restrict: 'A',
-        link,
-        require: ['ngModel']
-    };
-}]];

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/src/main/js/app/modules/form/validator/unique.directive.js
----------------------------------------------------------------------
diff --git a/modules/web-console/src/main/js/app/modules/form/validator/unique.directive.js b/modules/web-console/src/main/js/app/modules/form/validator/unique.directive.js
deleted file mode 100644
index 0e6af18..0000000
--- a/modules/web-console/src/main/js/app/modules/form/validator/unique.directive.js
+++ /dev/null
@@ -1,49 +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 ['igniteUnique', ['$parse', ($parse) => {
-    const link = (scope, el, attrs, [ngModel]) => {
-        if (_.isUndefined(attrs.igniteUnique) || !attrs.igniteUnique)
-            return;
-
-        const isNew = _.startsWith(attrs.name, 'new');
-        const property = attrs.igniteUniqueProperty;
-
-        ngModel.$validators.igniteUnique = (value) => {
-            const arr = $parse(attrs.igniteUnique)(scope);
-
-            // Return true in case if array not exist, array empty.
-            if (!arr || !arr.length)
-                return true;
-
-            const idx = _.findIndex(arr, (item) => (property ? item[property] : item) === value);
-
-            // In case of new element check all items.
-            if (isNew)
-                return idx < 0;
-
-            // Check for $index in case of editing in-place.
-            return (_.isNumber(scope.$index) && (idx < 0 || scope.$index === idx));
-        };
-    };
-
-    return {
-        restrict: 'A',
-        link,
-        require: ['ngModel']
-    };
-}]];

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/src/main/js/app/modules/getting-started/GettingStarted.provider.js
----------------------------------------------------------------------
diff --git a/modules/web-console/src/main/js/app/modules/getting-started/GettingStarted.provider.js b/modules/web-console/src/main/js/app/modules/getting-started/GettingStarted.provider.js
deleted file mode 100644
index cf9f561..0000000
--- a/modules/web-console/src/main/js/app/modules/getting-started/GettingStarted.provider.js
+++ /dev/null
@@ -1,112 +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 angular from 'angular';
-
-// Getting started pages.
-import PAGES from 'app/data/getting-started.json';
-
-angular
-    .module('ignite-console.getting-started', [])
-    .provider('igniteGettingStarted', function() {
-        const items = PAGES;
-
-        this.push = (before, data) => {
-            const idx = _.findIndex(items, {title: before});
-
-            if (idx < 0)
-                items.push(data);
-            else
-                items.splice(idx, 0, data);
-        };
-
-        this.update = (before, data) => {
-            const idx = _.findIndex(items, {title: before});
-
-            if (idx >= 0)
-                items[idx] = data;
-        };
-
-        this.$get = [function() {
-            return items;
-        }];
-    })
-    .service('gettingStarted', ['$rootScope', '$modal', 'igniteGettingStarted', function($root, $modal, igniteGettingStarted) {
-        const _model = igniteGettingStarted;
-
-        let _page = 0;
-
-        const scope = $root.$new();
-
-        scope.ui = {
-            showGettingStarted: false
-        };
-
-        function _fillPage() {
-            scope.title = _model[_page].title;
-            scope.message = _model[_page].message.join(' ');
-        }
-
-        scope.isFirst = () => _page === 0;
-
-        scope.isLast = () => _page === _model.length - 1;
-
-        scope.next = () => {
-            _page += 1;
-
-            _fillPage();
-        };
-
-        scope.prev = () => {
-            _page -= 1;
-
-            _fillPage();
-        };
-
-        const dialog = $modal({templateUrl: '/templates/getting-started.html', scope, placement: 'center', show: false, backdrop: 'static'});
-
-        scope.close = () => {
-            try {
-                localStorage.showGettingStarted = scope.ui.showGettingStarted;
-            }
-            catch (ignore) {
-                // No-op.
-            }
-
-            dialog.hide();
-        };
-
-        return {
-            tryShow: (force) => {
-                try {
-                    scope.ui.showGettingStarted = _.isNil(localStorage.showGettingStarted)
-                        || localStorage.showGettingStarted === 'true';
-                }
-                catch (ignore) {
-                    // No-op.
-                }
-
-                if (force || scope.ui.showGettingStarted) {
-                    _page = 0;
-
-                    _fillPage();
-
-                    dialog.$promise.then(dialog.show);
-                }
-            }
-        };
-    }]);

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/src/main/js/app/modules/loading/loading.css
----------------------------------------------------------------------
diff --git a/modules/web-console/src/main/js/app/modules/loading/loading.css b/modules/web-console/src/main/js/app/modules/loading/loading.css
deleted file mode 100644
index 87bbc6a..0000000
--- a/modules/web-console/src/main/js/app/modules/loading/loading.css
+++ /dev/null
@@ -1,73 +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-loading] {
-    position: relative;
-}
-
-.loading {
-    position: absolute;
-    bottom: 0;
-    left: 0;
-    right: 0;
-    top: 0;
-    z-index: 1001;
-    opacity: 0;
-    visibility: hidden;
-    background-color: white;
-    transition: visibility 0s 0.5s, opacity 0.5s linear;
-}
-
-.loading-active {
-    opacity: 1;
-    visibility: visible;
-    transition: opacity 0.5s linear;
-}
-
-.loading:before {
-    content: '';
-    display: inline-block;
-    height: 100%;
-    vertical-align: middle;
-}
-
-.loading .loading-wrapper {
-    display: inline-block;
-    vertical-align: middle;
-    position: relative;
-    width: 100%;
-}
-
-.loading.loading-top .loading-wrapper {
-    position: absolute;
-    top: 100px;
-    display: block;
-}
-
-.loading .loading-text {
-    font-size: 18px;
-    margin: 20px 0;
-    text-align: center;
-}
-
-.loading-opacity-80 {
-    opacity: 0.8;
-}
-
-.loading-max-foreground {
-    z-index: 99999;
-}

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/src/main/js/app/modules/loading/loading.directive.js
----------------------------------------------------------------------
diff --git a/modules/web-console/src/main/js/app/modules/loading/loading.directive.js b/modules/web-console/src/main/js/app/modules/loading/loading.directive.js
deleted file mode 100644
index 064b4c2..0000000
--- a/modules/web-console/src/main/js/app/modules/loading/loading.directive.js
+++ /dev/null
@@ -1,51 +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 templateUrl from './loading.jade';
-import './loading.css';
-
-export default ['igniteLoading', ['IgniteLoading', '$templateCache', '$compile', (Loading, $templateCache, $compile) => {
-    const link = (scope, element) => {
-        const compiledTemplate = $compile($templateCache.get(templateUrl));
-
-        const build = () => {
-            scope.position = scope.position || 'middle';
-
-            const loading = compiledTemplate(scope);
-
-            if (!scope.loading) {
-                scope.loading = loading;
-
-                Loading.add(scope.key || 'defaultSpinnerKey', scope.loading);
-                element.append(scope.loading);
-            }
-        };
-
-        build();
-    };
-
-    return {
-        scope: {
-            key: '@igniteLoading',
-            text: '@?igniteLoadingText',
-            class: '@?igniteLoadingClass',
-            position: '@?igniteLoadingPosition'
-        },
-        restrict: 'A',
-        link
-    };
-}]];

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/src/main/js/app/modules/loading/loading.jade
----------------------------------------------------------------------
diff --git a/modules/web-console/src/main/js/app/modules/loading/loading.jade b/modules/web-console/src/main/js/app/modules/loading/loading.jade
deleted file mode 100644
index cc6cf45..0000000
--- a/modules/web-console/src/main/js/app/modules/loading/loading.jade
+++ /dev/null
@@ -1,23 +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.
-
-.loading.loading-opacity-80(ng-class='[class, "loading-" + position]')
-    .loading-wrapper
-        .spinner
-            .bounce1
-            .bounce2
-            .bounce3
-        .loading-text {{ text }}


[52/52] ignite git commit: Merge branch ignite-1.7.2 to master.

Posted by ak...@apache.org.
Merge branch ignite-1.7.2 to master.


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

Branch: refs/heads/master
Commit: 39ec7d06be4ed71f7c7425c0fcd8a244caa28550
Parents: 31b9bb8 2a117fe
Author: Alexey Kuznetsov <ak...@apache.org>
Authored: Fri Sep 9 10:20:21 2016 +0700
Committer: Alexey Kuznetsov <ak...@apache.org>
Committed: Fri Sep 9 10:20:21 2016 +0700

----------------------------------------------------------------------
 .../visor/event/VisorGridDiscoveryEventV2.java  |   80 +
 .../visor/node/VisorNodeDataCollectorJob.java   |   10 +-
 .../internal/visor/util/VisorEventMapper.java   |   96 +-
 .../internal/visor/util/VisorTaskUtils.java     |   22 +-
 modules/web-agent/.gitignore                    |    2 -
 modules/web-agent/README.txt                    |   88 -
 .../web-agent/assembly/release-web-agent.xml    |   72 -
 modules/web-agent/bin/ignite-web-agent.bat      |   70 -
 modules/web-agent/bin/ignite-web-agent.sh       |   87 -
 modules/web-agent/demo/README.txt               |    4 -
 modules/web-agent/demo/db-init.sql              |  102 -
 modules/web-agent/jdbc-drivers/README.txt       |   10 -
 modules/web-agent/logs/README.txt               |    5 -
 modules/web-agent/pom.xml                       |  189 -
 .../console/agent/AgentConfiguration.java       |  268 --
 .../ignite/console/agent/AgentLauncher.java     |  344 --
 .../apache/ignite/console/agent/AgentUtils.java |  111 -
 .../console/agent/handlers/AbstractHandler.java |  110 -
 .../console/agent/handlers/DatabaseHandler.java |  298 --
 .../console/agent/handlers/RestHandler.java     |  276 --
 .../ignite/console/demo/AgentClusterDemo.java   |  638 ----
 .../ignite/console/demo/AgentMetadataDemo.java  |   92 -
 .../apache/ignite/console/demo/model/Car.java   |  152 -
 .../ignite/console/demo/model/Country.java      |  152 -
 .../ignite/console/demo/model/Department.java   |  152 -
 .../ignite/console/demo/model/Employee.java     |  356 --
 .../ignite/console/demo/model/Parking.java      |  152 -
 .../src/main/resources/log4j.properties         |   53 -
 modules/web-console/.gitignore                  |    6 +
 modules/web-console/DEVNOTES.txt                |   22 +-
 modules/web-console/backend/.babelrc            |    9 +
 modules/web-console/backend/.eslintrc           |  188 +
 modules/web-console/backend/.gitignore          |    8 +
 .../web-console/backend/agent_dists/README.txt  |    7 +
 modules/web-console/backend/app/agent.js        |  753 ++++
 modules/web-console/backend/app/app.js          |   61 +
 modules/web-console/backend/app/browser.js      |  404 ++
 modules/web-console/backend/app/configure.js    |   86 +
 modules/web-console/backend/app/index.js        |  116 +
 modules/web-console/backend/app/mongo.js        |  673 ++++
 modules/web-console/backend/app/nconf.js        |   48 +
 modules/web-console/backend/app/routes.js       |   64 +
 modules/web-console/backend/app/settings.js     |   80 +
 .../backend/config/settings.json.sample         |   30 +
 .../backend/errors/AppErrorException.js         |   36 +
 .../backend/errors/AuthFailedException.js       |   30 +
 .../backend/errors/DuplicateKeyException.js     |   28 +
 .../backend/errors/IllegalAccessError.js        |   29 +
 .../backend/errors/IllegalArgumentException.js  |   29 +
 .../backend/errors/MissingResourceException.js  |   30 +
 .../backend/errors/ServerErrorException.js      |   36 +
 modules/web-console/backend/errors/index.js     |   39 +
 modules/web-console/backend/index.js            |   19 +
 modules/web-console/backend/injector.js         |   30 +
 modules/web-console/backend/middlewares/api.js  |   44 +
 modules/web-console/backend/middlewares/host.js |   39 +
 modules/web-console/backend/middlewares/user.js |   36 +
 modules/web-console/backend/package.json        |   71 +
 modules/web-console/backend/routes/admin.js     |   84 +
 modules/web-console/backend/routes/agent.js     |   53 +
 modules/web-console/backend/routes/caches.js    |   65 +
 modules/web-console/backend/routes/clusters.js  |   64 +
 .../web-console/backend/routes/configuration.js |   41 +
 modules/web-console/backend/routes/demo.js      |  133 +
 .../web-console/backend/routes/demo/caches.json |   87 +
 .../backend/routes/demo/clusters.json           |   50 +
 .../backend/routes/demo/domains.json            |  307 ++
 .../web-console/backend/routes/demo/igfss.json  |   10 +
 modules/web-console/backend/routes/domains.js   |   76 +
 modules/web-console/backend/routes/igfss.js     |   65 +
 modules/web-console/backend/routes/notebooks.js |   80 +
 modules/web-console/backend/routes/profile.js   |   73 +
 modules/web-console/backend/routes/public.js    |  168 +
 modules/web-console/backend/services/agents.js  |   82 +
 modules/web-console/backend/services/auth.js    |   47 +
 modules/web-console/backend/services/caches.js  |  144 +
 .../web-console/backend/services/clusters.js    |  141 +
 .../backend/services/configurations.js          |   59 +
 modules/web-console/backend/services/domains.js |  187 +
 modules/web-console/backend/services/igfss.js   |  136 +
 modules/web-console/backend/services/mails.js   |  131 +
 .../web-console/backend/services/notebooks.js   |  104 +
 .../web-console/backend/services/sessions.js    |   63 +
 modules/web-console/backend/services/spaces.js  |   75 +
 modules/web-console/backend/services/users.js   |  229 ++
 .../backend/test/config/settings.json           |   20 +
 .../web-console/backend/test/data/accounts.json |   18 +
 .../web-console/backend/test/data/caches.json   |   87 +
 .../web-console/backend/test/data/clusters.json |   50 +
 .../web-console/backend/test/data/domains.json  |  307 ++
 .../web-console/backend/test/data/igfss.json    |   10 +
 modules/web-console/backend/test/injector.js    |   31 +
 .../backend/test/unit/CacheService.test.js      |  192 +
 .../backend/test/unit/ClusterService.test.js    |  190 +
 .../backend/test/unit/DomainService.test.js     |  198 +
 .../backend/test/unit/IgfsService.test.js       |  190 +
 .../docker/compose/backend/.dockerignore        |    1 +
 .../docker/compose/backend/Dockerfile           |   30 +
 .../web-console/docker/compose/backend/build.sh |   57 +
 .../docker/compose/docker-compose.yml           |   59 +
 .../docker/compose/frontend/.dockerignore       |    3 +
 .../docker/compose/frontend/Dockerfile          |   32 +
 .../docker/compose/frontend/DockerfileBuild     |   30 +
 .../docker/compose/frontend/build.sh            |   59 +
 .../docker/compose/frontend/nginx/nginx.conf    |   57 +
 .../compose/frontend/nginx/web-console.conf     |   59 +
 .../web-console/docker/standalone/.dockerignore |    2 +
 .../web-console/docker/standalone/Dockerfile    |   87 +
 modules/web-console/docker/standalone/build.sh  |   59 +
 .../docker/standalone/docker-compose.yml        |   41 +
 .../web-console/docker/standalone/entrypoint.sh |   23 +
 .../docker/standalone/nginx/nginx.conf          |   55 +
 .../docker/standalone/nginx/web-console.conf    |   54 +
 modules/web-console/frontend/.babelrc           |    9 +
 modules/web-console/frontend/.eslintrc          |  202 +
 modules/web-console/frontend/.gitignore         |    7 +
 modules/web-console/frontend/app/app.config.js  |   86 +
 modules/web-console/frontend/app/app.js         |  270 ++
 .../frontend/app/controllers/auth.controller.js |   30 +
 .../controllers/reset-password.controller.js    |   50 +
 .../web-console/frontend/app/data/colors.json   |   22 +
 .../frontend/app/data/countries.json            |   94 +
 .../frontend/app/data/demo-info.json            |   14 +
 .../frontend/app/data/event-types.json          |  169 +
 .../frontend/app/data/getting-started.json      |  109 +
 .../frontend/app/data/java-classes.json         |   19 +
 .../frontend/app/data/java-keywords.json        |   55 +
 .../frontend/app/data/java-primitives.json      |    9 +
 .../frontend/app/data/pom-dependencies.json     |   20 +
 .../frontend/app/decorator/select.js            |   77 +
 .../frontend/app/decorator/tooltip.js           |   56 +
 .../app/directives/auto-focus.directive.js      |   26 +
 .../app/directives/bs-affix-update.directive.js |   34 +
 .../app/directives/centered/centered.css        |   37 +
 .../directives/centered/centered.directive.js   |   26 +
 .../directives/copy-to-clipboard.directive.js   |   29 +
 .../hide-on-state-change.directive.js           |   31 +
 .../information/information.directive.js        |   30 +
 .../app/directives/information/information.jade |   20 +
 .../app/directives/information/information.scss |   56 +
 .../frontend/app/directives/match.directive.js  |   27 +
 .../app/directives/on-click-focus.directive.js  |   26 +
 .../directives/on-enter-focus-move.directive.js |   29 +
 .../app/directives/on-enter.directive.js        |   32 +
 .../app/directives/on-escape.directive.js       |   32 +
 .../ui-ace-docker/ui-ace-docker.controller.js   |   33 +
 .../ui-ace-docker/ui-ace-docker.directive.js    |   46 +
 .../directives/ui-ace-docker/ui-ace-docker.jade |   31 +
 .../ui-ace-java/ui-ace-java.controller.js       |   32 +
 .../ui-ace-java/ui-ace-java.directive.js        |  147 +
 .../app/directives/ui-ace-java/ui-ace-java.jade |   22 +
 .../ui-ace-pojos/ui-ace-pojos.controller.js     |   95 +
 .../ui-ace-pojos/ui-ace-pojos.directive.js      |   46 +
 .../directives/ui-ace-pojos/ui-ace-pojos.jade   |   40 +
 .../ui-ace-pom/ui-ace-pom.controller.js         |   33 +
 .../ui-ace-pom/ui-ace-pom.directive.js          |   41 +
 .../app/directives/ui-ace-pom/ui-ace-pom.jade   |   17 +
 .../app/directives/ui-ace-tabs.directive.js     |   24 +
 .../ui-ace-xml/ui-ace-xml.controller.js         |   27 +
 .../ui-ace-xml/ui-ace-xml.directive.js          |  147 +
 .../app/directives/ui-ace-xml/ui-ace-xml.jade   |   17 +
 .../frontend/app/filters/byName.filter.js       |   23 +
 .../app/filters/domainsValidation.filter.js     |   33 +
 .../frontend/app/filters/duration.filter.js     |   38 +
 .../frontend/app/filters/hasPojo.filter.js      |   18 +
 .../frontend/app/helpers/jade/form.jade         |   27 +
 .../helpers/jade/form/form-field-checkbox.jade  |   38 +
 .../helpers/jade/form/form-field-datalist.jade  |   51 +
 .../app/helpers/jade/form/form-field-down.jade  |   18 +
 .../helpers/jade/form/form-field-dropdown.jade  |   50 +
 .../helpers/jade/form/form-field-feedback.jade  |   29 +
 .../app/helpers/jade/form/form-field-label.jade |   23 +
 .../helpers/jade/form/form-field-number.jade    |   52 +
 .../app/helpers/jade/form/form-field-text.jade  |   47 +
 .../app/helpers/jade/form/form-field-up.jade    |   18 +
 .../app/helpers/jade/form/form-group.jade       |   23 +
 .../frontend/app/helpers/jade/mixins.jade       |  541 +++
 .../frontend/app/modules/Demo/Demo.module.js    |  166 +
 .../frontend/app/modules/ace.module.js          |  269 ++
 .../frontend/app/modules/agent/agent.module.js  |  341 ++
 .../app/modules/branding/branding.module.js     |   45 +
 .../app/modules/branding/branding.provider.js   |  111 +
 .../app/modules/branding/features.directive.js  |   35 +
 .../app/modules/branding/footer.directive.js    |   34 +
 .../modules/branding/header-logo.directive.js   |   34 +
 .../app/modules/branding/header-logo.jade       |   18 +
 .../modules/branding/header-title.directive.js  |   35 +
 .../branding/powered-by-apache.directive.js     |   35 +
 .../app/modules/branding/powered-by-apache.jade |   18 +
 .../app/modules/branding/terms.directive.js     |   30 +
 .../configuration/EventGroups.provider.js       |   30 +
 .../modules/configuration/Sidebar.provider.js   |   39 +
 .../configuration/configuration.module.js       |   41 +
 .../configuration/generator/Docker.service.js   |   78 +
 .../configuration/generator/Java.service.js     |   21 +
 .../configuration/generator/Pom.service.js      |  226 ++
 .../configuration/generator/Xml.service.js      |   21 +
 .../modules/configuration/sidebar.directive.js  |   30 +
 .../modules/dialog/dialog-content.directive.js  |   31 +
 .../modules/dialog/dialog-title.directive.js    |   31 +
 .../app/modules/dialog/dialog.controller.js     |   40 +
 .../app/modules/dialog/dialog.directive.js      |   32 +
 .../app/modules/dialog/dialog.factory.js        |   32 +
 .../frontend/app/modules/dialog/dialog.jade     |   26 +
 .../app/modules/dialog/dialog.module.js         |   32 +
 .../field/bs-select-placeholder.directive.js    |   47 +
 .../app/modules/form/field/down.directive.js    |   39 +
 .../app/modules/form/field/feedback.scss        |   37 +
 .../frontend/app/modules/form/field/field.scss  |   43 +
 .../field/form-control-feedback.directive.js    |   40 +
 .../form/field/input/autofocus.directive.js     |   30 +
 .../app/modules/form/field/input/select.scss    |   21 +
 .../app/modules/form/field/input/text.scss      |   41 +
 .../app/modules/form/field/label.directive.js   |   47 +
 .../app/modules/form/field/tooltip.directive.js |   49 +
 .../app/modules/form/field/up.directive.js      |   39 +
 .../frontend/app/modules/form/form.module.js    |   96 +
 .../app/modules/form/group/add.directive.js     |   40 +
 .../app/modules/form/group/tooltip.directive.js |   40 +
 .../app/modules/form/panel/chevron.directive.js |   53 +
 .../app/modules/form/panel/field.directive.js   |   69 +
 .../app/modules/form/panel/panel.directive.js   |   37 +
 .../app/modules/form/panel/revert.directive.js  |   54 +
 .../form/validator/ipaddress.directive.js       |   86 +
 .../validator/java-built-in-class.directive.js  |   31 +
 .../form/validator/java-identifier.directive.js |   31 +
 .../form/validator/java-keywords.directive.js   |   42 +
 .../validator/java-package-name.directive.js    |   31 +
 .../java-package-specified.directive.js         |   34 +
 .../form/validator/property-unique.directive.js |   47 +
 .../property-value-specified.directive.js       |   31 +
 .../modules/form/validator/unique.directive.js  |   49 +
 .../modules/form/validator/uuid.directive.js    |   37 +
 .../getting-started/GettingStarted.provider.js  |  112 +
 .../frontend/app/modules/loading/loading.css    |   73 +
 .../app/modules/loading/loading.directive.js    |   51 +
 .../frontend/app/modules/loading/loading.jade   |   23 +
 .../app/modules/loading/loading.module.js       |   26 +
 .../app/modules/loading/loading.service.js      |   48 +
 .../app/modules/navbar/Navbar.provider.js       |   28 +
 .../app/modules/navbar/Userbar.provider.js      |   28 +
 .../app/modules/navbar/navbar.directive.js      |   30 +
 .../app/modules/navbar/navbar.module.js         |   33 +
 .../app/modules/navbar/userbar.directive.js     |   48 +
 .../frontend/app/modules/socket.module.js       |   41 +
 .../frontend/app/modules/sql/Notebook.data.js   |  157 +
 .../app/modules/sql/Notebook.service.js         |   74 +
 .../app/modules/sql/notebook.controller.js      |   60 +
 .../app/modules/sql/scan-filter-input.jade      |   39 +
 .../modules/sql/scan-filter-input.service.js    |   51 +
 .../frontend/app/modules/sql/sql.controller.js  | 1632 ++++++++
 .../frontend/app/modules/sql/sql.module.js      |   60 +
 .../frontend/app/modules/states/admin.state.js  |   35 +
 .../app/modules/states/configuration.state.js   |   97 +
 .../configuration/Configuration.resource.js     |   42 +
 .../configuration/caches/concurrency.jade       |   65 +
 .../states/configuration/caches/general.jade    |   66 +
 .../states/configuration/caches/memory.jade     |  102 +
 .../configuration/caches/node-filter.jade       |  108 +
 .../states/configuration/caches/query.jade      |   95 +
 .../states/configuration/caches/rebalance.jade  |   65 +
 .../configuration/caches/server-near-cache.jade |   51 +
 .../states/configuration/caches/statistics.jade |   39 +
 .../states/configuration/caches/store.jade      |  244 ++
 .../states/configuration/clusters/atomic.jade   |   53 +
 .../configuration/clusters/attributes.jade      |   57 +
 .../states/configuration/clusters/binary.jade   |   77 +
 .../configuration/clusters/cache-key-cfg.jade   |   53 +
 .../configuration/clusters/collision.jade       |   62 +
 .../clusters/collision/custom.jade              |   24 +
 .../clusters/collision/fifo-queue.jade          |   27 +
 .../clusters/collision/job-stealing.jade        |   63 +
 .../clusters/collision/priority-queue.jade      |   42 +
 .../configuration/clusters/communication.jade   |   99 +
 .../configuration/clusters/connector.jade       |  103 +
 .../configuration/clusters/deployment.jade      |  113 +
 .../configuration/clusters/discovery.jade       |   87 +
 .../states/configuration/clusters/events.jade   |   37 +
 .../states/configuration/clusters/failover.jade |   72 +
 .../states/configuration/clusters/general.jade  |   73 +
 .../clusters/general/discovery/cloud.jade       |  134 +
 .../clusters/general/discovery/google.jade      |   38 +
 .../clusters/general/discovery/jdbc.jade        |   32 +
 .../clusters/general/discovery/multicast.jade   |   99 +
 .../clusters/general/discovery/s3.jade          |   27 +
 .../clusters/general/discovery/shared.jade      |   23 +
 .../clusters/general/discovery/vm.jade          |   79 +
 .../clusters/general/discovery/zookeeper.jade   |   83 +
 .../bounded-exponential-backoff.jade            |   27 +
 .../discovery/zookeeper/retrypolicy/custom.jade |   24 +
 .../retrypolicy/exponential-backoff.jade        |   27 +
 .../zookeeper/retrypolicy/forever.jade          |   22 +
 .../zookeeper/retrypolicy/n-times.jade          |   25 +
 .../zookeeper/retrypolicy/one-time.jade         |   23 +
 .../zookeeper/retrypolicy/until-elapsed.jade    |   25 +
 .../states/configuration/clusters/igfs.jade     |   37 +
 .../states/configuration/clusters/logger.jade   |   66 +
 .../configuration/clusters/logger/custom.jade   |   25 +
 .../configuration/clusters/logger/log4j.jade    |   50 +
 .../configuration/clusters/logger/log4j2.jade   |   39 +
 .../configuration/clusters/marshaller.jade      |   75 +
 .../states/configuration/clusters/metrics.jade  |   51 +
 .../states/configuration/clusters/ssl.jade      |  109 +
 .../states/configuration/clusters/swap.jade     |   71 +
 .../states/configuration/clusters/thread.jade   |   48 +
 .../states/configuration/clusters/time.jade     |   47 +
 .../configuration/clusters/transactions.jade    |   69 +
 .../states/configuration/domains/general.jade   |   46 +
 .../states/configuration/domains/query.jade     |  170 +
 .../states/configuration/domains/store.jade     |  126 +
 .../modules/states/configuration/igfs/dual.jade |   42 +
 .../states/configuration/igfs/fragmentizer.jade |   43 +
 .../states/configuration/igfs/general.jade      |   54 +
 .../modules/states/configuration/igfs/ipc.jade  |   60 +
 .../modules/states/configuration/igfs/misc.jade |  108 +
 .../states/configuration/igfs/secondary.jade    |   44 +
 .../configuration/preview-panel.directive.js    |  239 ++
 .../summary/summary-tabs.directive.js           |   50 +
 .../configuration/summary/summary.controller.js |  365 ++
 .../frontend/app/modules/states/errors.state.js |   43 +
 .../frontend/app/modules/states/logout.state.js |   35 +
 .../app/modules/states/password.state.js        |   46 +
 .../app/modules/states/profile.state.js         |   35 +
 .../frontend/app/modules/states/signin.state.js |   43 +
 .../app/modules/user/AclRoute.provider.js       |   47 +
 .../frontend/app/modules/user/Auth.service.js   |   56 +
 .../frontend/app/modules/user/User.service.js   |   51 +
 .../frontend/app/modules/user/permissions.js    |   28 +
 .../frontend/app/modules/user/user.module.js    |   73 +
 .../app/modules/version/Version.provider.js     |   32 +
 .../app/services/ChartColors.service.js         |   22 +
 .../frontend/app/services/Clone.service.js      |   64 +
 .../frontend/app/services/Confirm.service.js    |   68 +
 .../app/services/ConfirmBatch.service.js        |   92 +
 .../app/services/CopyToClipboard.service.js     |   50 +
 .../frontend/app/services/Countries.service.js  |   31 +
 .../app/services/ErrorPopover.service.js        |  126 +
 .../frontend/app/services/Focus.service.js      |   33 +
 .../frontend/app/services/FormUtils.service.js  |  435 +++
 .../app/services/InetAddress.service.js         |   53 +
 .../frontend/app/services/JavaTypes.service.js  |   93 +
 .../app/services/LegacyTable.service.js         |  209 ++
 .../app/services/LegacyUtils.service.js         |  572 +++
 .../frontend/app/services/Messages.service.js   |   63 +
 .../app/services/ModelNormalizer.service.js     |   59 +
 .../app/services/UnsavedChangesGuard.service.js |   38 +
 modules/web-console/frontend/app/vendor.js      |   55 +
 .../frontend/controllers/admin-controller.js    |   92 +
 .../frontend/controllers/caches-controller.js   |  524 +++
 .../frontend/controllers/clusters-controller.js |  689 ++++
 .../frontend/controllers/domains-controller.js  | 1792 +++++++++
 .../frontend/controllers/igfs-controller.js     |  416 +++
 .../frontend/controllers/profile-controller.js  |   94 +
 .../frontend/generator/generator-common.js      |  612 +++
 .../frontend/generator/generator-java.js        | 3534 ++++++++++++++++++
 .../frontend/generator/generator-optional.js    |   25 +
 .../frontend/generator/generator-properties.js  |  175 +
 .../frontend/generator/generator-readme.js      |   85 +
 .../frontend/generator/generator-xml.js         | 2093 +++++++++++
 .../frontend/gulpfile.babel.js/index.js         |   26 +
 .../frontend/gulpfile.babel.js/paths.js         |   74 +
 .../frontend/gulpfile.babel.js/tasks/build.js   |   21 +
 .../frontend/gulpfile.babel.js/tasks/bundle.js  |   32 +
 .../frontend/gulpfile.babel.js/tasks/clean.js   |   32 +
 .../frontend/gulpfile.babel.js/tasks/copy.js    |   33 +
 .../gulpfile.babel.js/tasks/ignite-modules.js   |   55 +
 .../frontend/gulpfile.babel.js/tasks/jade.js    |   40 +
 .../frontend/gulpfile.babel.js/tasks/test.js    |   92 +
 .../frontend/gulpfile.babel.js/tasks/watch.js   |   31 +
 .../gulpfile.babel.js/webpack/common.js         |  189 +
 .../webpack/environments/development.js         |   69 +
 .../webpack/environments/production.js          |   45 +
 .../frontend/gulpfile.babel.js/webpack/index.js |   32 +
 .../webpack/plugins/progress.js                 |   82 +
 .../frontend/ignite_modules/README.txt          |    6 +
 .../frontend/ignite_modules/index.js            |   27 +
 modules/web-console/frontend/package.json       |  125 +
 modules/web-console/frontend/public/favicon.ico |  Bin 0 -> 1150 bytes
 .../frontend/public/images/cache.png            |  Bin 0 -> 23700 bytes
 .../frontend/public/images/cluster.png          |  Bin 0 -> 29376 bytes
 .../frontend/public/images/docker.png           |  Bin 0 -> 521 bytes
 .../frontend/public/images/domains.png          |  Bin 0 -> 23828 bytes
 .../web-console/frontend/public/images/igfs.png |  Bin 0 -> 14307 bytes
 .../frontend/public/images/ignite-logo.png      |  Bin 0 -> 1982 bytes
 .../frontend/public/images/ignite-logo@2x.png   |  Bin 0 -> 3325 bytes
 .../frontend/public/images/ignite-puzzle.png    |  Bin 0 -> 71974 bytes
 .../web-console/frontend/public/images/java.png |  Bin 0 -> 170 bytes
 .../frontend/public/images/pb-ignite.png        |  Bin 0 -> 3493 bytes
 .../frontend/public/images/pb-ignite@2x.png     |  Bin 0 -> 8558 bytes
 .../frontend/public/images/query-chart.png      |  Bin 0 -> 16637 bytes
 .../frontend/public/images/query-metadata.png   |  Bin 0 -> 32298 bytes
 .../frontend/public/images/query-table.png      |  Bin 0 -> 29189 bytes
 .../frontend/public/images/summary.png          |  Bin 0 -> 31997 bytes
 .../web-console/frontend/public/images/xml.png  |  Bin 0 -> 232 bytes
 .../public/stylesheets/_bootstrap-custom.scss   |   65 +
 .../stylesheets/_bootstrap-variables.scss       |  891 +++++
 .../stylesheets/_font-awesome-custom.scss       |   32 +
 .../public/stylesheets/blocks/error.scss        |   31 +
 .../frontend/public/stylesheets/style.scss      | 2171 +++++++++++
 .../frontend/public/stylesheets/variables.scss  |   28 +
 .../frontend/test/e2e/exampe.test.js            |   40 +
 modules/web-console/frontend/test/karma.conf.js |  113 +
 .../frontend/test/protractor.conf.js            |   50 +
 .../frontend/test/unit/JavaTypes.test.js        |   69 +
 .../frontend/test/unit/UserAuth.test.js         |   35 +
 modules/web-console/frontend/views/403.jade     |   22 +
 modules/web-console/frontend/views/404.jade     |   22 +
 modules/web-console/frontend/views/base.jade    |   22 +
 .../frontend/views/configuration/caches.jade    |   53 +
 .../frontend/views/configuration/clusters.jade  |   66 +
 .../views/configuration/domains-import.jade     |  223 ++
 .../frontend/views/configuration/domains.jade   |   66 +
 .../frontend/views/configuration/igfs.jade      |   51 +
 .../frontend/views/configuration/sidebar.jade   |   29 +
 .../summary-project-structure.jade              |   27 +
 .../views/configuration/summary-tabs.jade       |   25 +
 .../frontend/views/configuration/summary.jade   |  122 +
 .../frontend/views/includes/footer.jade         |   23 +
 .../frontend/views/includes/header.jade         |   51 +
 modules/web-console/frontend/views/index.jade   |   47 +
 modules/web-console/frontend/views/reset.jade   |   48 +
 .../frontend/views/settings/admin.jade          |   76 +
 .../frontend/views/settings/profile.jade        |   76 +
 modules/web-console/frontend/views/signin.jade  |  163 +
 .../frontend/views/sql/cache-metadata.jade      |   40 +
 .../frontend/views/sql/chart-settings.jade      |   40 +
 .../frontend/views/sql/notebook-new.jade        |   31 +
 .../frontend/views/sql/paragraph-rate.jade      |   31 +
 modules/web-console/frontend/views/sql/sql.jade |  193 +
 .../views/templates/agent-download.jade         |   48 +
 .../frontend/views/templates/alert.jade         |   21 +
 .../frontend/views/templates/batch-confirm.jade |   32 +
 .../frontend/views/templates/clone.jade         |   37 +
 .../frontend/views/templates/confirm.jade       |   31 +
 .../frontend/views/templates/demo-info.jade     |   45 +
 .../frontend/views/templates/dropdown.jade      |   24 +
 .../views/templates/getting-started.jade        |   32 +
 .../frontend/views/templates/message.jade       |   26 +
 .../frontend/views/templates/pagination.jade    |   32 +
 .../frontend/views/templates/select.jade        |   26 +
 .../views/templates/validation-error.jade       |   25 +
 modules/web-console/pom.xml                     |   33 +-
 modules/web-console/src/main/js/.babelrc        |    3 -
 modules/web-console/src/main/js/.eslintrc       |  202 -
 modules/web-console/src/main/js/.gitignore      |    9 -
 .../web-console/src/main/js/app/app.config.js   |   86 -
 modules/web-console/src/main/js/app/app.js      |  274 --
 .../main/js/app/controllers/auth.controller.js  |   30 -
 .../js/app/controllers/notebooks.controller.js  |   69 -
 .../controllers/reset-password.controller.js    |   51 -
 .../src/main/js/app/data/colors.json            |   22 -
 .../src/main/js/app/data/countries.json         |   94 -
 .../src/main/js/app/data/demo-info.json         |   14 -
 .../src/main/js/app/data/event-types.json       |  169 -
 .../src/main/js/app/data/getting-started.json   |  109 -
 .../src/main/js/app/data/java-classes.json      |   18 -
 .../src/main/js/app/data/java-keywords.json     |   55 -
 .../src/main/js/app/data/java-primitives.json   |    9 -
 .../src/main/js/app/data/pom-dependencies.json  |   20 -
 .../src/main/js/app/decorator/select.js         |   77 -
 .../src/main/js/app/decorator/tooltip.js        |   56 -
 .../js/app/directives/auto-focus.directive.js   |   26 -
 .../app/directives/bs-affix-update.directive.js |   34 -
 .../js/app/directives/centered/centered.css     |   37 -
 .../directives/centered/centered.directive.js   |   26 -
 .../directives/copy-to-clipboard.directive.js   |   29 -
 .../hide-on-state-change.directive.js           |   31 -
 .../information/information.directive.js        |   30 -
 .../app/directives/information/information.jade |   20 -
 .../app/directives/information/information.scss |   56 -
 .../main/js/app/directives/match.directive.js   |   27 -
 .../app/directives/on-click-focus.directive.js  |   26 -
 .../directives/on-enter-focus-move.directive.js |   29 -
 .../js/app/directives/on-enter.directive.js     |   32 -
 .../js/app/directives/on-escape.directive.js    |   32 -
 .../ui-ace-docker/ui-ace-docker.controller.js   |   33 -
 .../ui-ace-docker/ui-ace-docker.directive.js    |   46 -
 .../directives/ui-ace-docker/ui-ace-docker.jade |   31 -
 .../ui-ace-java/ui-ace-java.controller.js       |   32 -
 .../ui-ace-java/ui-ace-java.directive.js        |  133 -
 .../app/directives/ui-ace-java/ui-ace-java.jade |   22 -
 .../ui-ace-pojos/ui-ace-pojos.controller.js     |   95 -
 .../ui-ace-pojos/ui-ace-pojos.directive.js      |   46 -
 .../directives/ui-ace-pojos/ui-ace-pojos.jade   |   40 -
 .../ui-ace-pom/ui-ace-pom.controller.js         |   33 -
 .../ui-ace-pom/ui-ace-pom.directive.js          |   41 -
 .../app/directives/ui-ace-pom/ui-ace-pom.jade   |   17 -
 .../js/app/directives/ui-ace-tabs.directive.js  |   23 -
 .../ui-ace-xml/ui-ace-xml.controller.js         |   27 -
 .../ui-ace-xml/ui-ace-xml.directive.js          |  133 -
 .../app/directives/ui-ace-xml/ui-ace-xml.jade   |   17 -
 .../src/main/js/app/filters/byName.filter.js    |   23 -
 .../js/app/filters/domainsValidation.filter.js  |   33 -
 .../src/main/js/app/filters/hasPojo.filter.js   |   18 -
 .../src/main/js/app/helpers/jade/mixins.jade    |  588 ---
 .../src/main/js/app/modules/Demo/Demo.module.js |  166 -
 .../js/app/modules/Version/Version.provider.js  |   32 -
 .../src/main/js/app/modules/ace.module.js       |  269 --
 .../main/js/app/modules/agent/agent.module.js   |  323 --
 .../js/app/modules/branding/branding.module.js  |   45 -
 .../app/modules/branding/branding.provider.js   |  111 -
 .../app/modules/branding/features.directive.js  |   35 -
 .../js/app/modules/branding/footer.directive.js |   34 -
 .../modules/branding/header-logo.directive.js   |   34 -
 .../js/app/modules/branding/header-logo.jade    |   18 -
 .../modules/branding/header-title.directive.js  |   35 -
 .../branding/powered-by-apache.directive.js     |   35 -
 .../app/modules/branding/powered-by-apache.jade |   18 -
 .../js/app/modules/branding/terms.directive.js  |   30 -
 .../configuration/EventGroups.provider.js       |   30 -
 .../modules/configuration/Sidebar.provider.js   |   39 -
 .../configuration/configuration.module.js       |   41 -
 .../configuration/generator/Docker.service.js   |   78 -
 .../configuration/generator/Java.service.js     |   21 -
 .../configuration/generator/Pom.service.js      |  210 --
 .../configuration/generator/Xml.service.js      |   21 -
 .../modules/configuration/sidebar.directive.js  |   30 -
 .../modules/dialog/dialog-content.directive.js  |   31 -
 .../modules/dialog/dialog-title.directive.js    |   31 -
 .../js/app/modules/dialog/dialog.controller.js  |   40 -
 .../js/app/modules/dialog/dialog.directive.js   |   32 -
 .../js/app/modules/dialog/dialog.factory.js     |   32 -
 .../src/main/js/app/modules/dialog/dialog.jade  |   26 -
 .../main/js/app/modules/dialog/dialog.module.js |   32 -
 .../field/bs-select-placeholder.directive.js    |   47 -
 .../js/app/modules/form/field/down.directive.js |   43 -
 .../modules/form/field/dropdown.directive.js    |   83 -
 .../js/app/modules/form/field/dropdown.jade     |   61 -
 .../main/js/app/modules/form/field/field.css    |   23 -
 .../app/modules/form/field/field.directive.js   |   44 -
 .../main/js/app/modules/form/field/field.jade   |   27 -
 .../field/form-control-feedback.directive.js    |   40 -
 .../form/field/input/autofocus.directive.js     |   30 -
 .../form/field/input/checkbox.directive.js      |   66 -
 .../app/modules/form/field/input/checkbox.jade  |   30 -
 .../form/field/input/datalist.directive.js      |  122 -
 .../app/modules/form/field/input/datalist.jade  |   51 -
 .../form/field/input/number.directive.js        |   76 -
 .../js/app/modules/form/field/input/number.jade |   50 -
 .../js/app/modules/form/field/input/text.css    |   41 -
 .../modules/form/field/input/text.directive.js  |  126 -
 .../js/app/modules/form/field/input/text.jade   |   48 -
 .../app/modules/form/field/label.directive.js   |   47 -
 .../app/modules/form/field/tooltip.directive.js |   49 -
 .../js/app/modules/form/field/up.directive.js   |   44 -
 .../src/main/js/app/modules/form/form.module.js |  101 -
 .../js/app/modules/form/group/add.directive.js  |   40 -
 .../app/modules/form/group/group.directive.js   |   81 -
 .../main/js/app/modules/form/group/group.jade   |   21 -
 .../app/modules/form/group/table.directive.js   |   29 -
 .../main/js/app/modules/form/group/table.jade   |   17 -
 .../app/modules/form/group/tooltip.directive.js |   40 -
 .../app/modules/form/panel/chevron.directive.js |   53 -
 .../app/modules/form/panel/panel.directive.js   |   37 -
 .../app/modules/form/panel/revert.directive.js  |   53 -
 .../form/validator/ipaddress.directive.js       |   86 -
 .../validator/java-built-in-class.directive.js  |   31 -
 .../form/validator/java-identifier.directive.js |   31 -
 .../form/validator/java-keywords.directive.js   |   42 -
 .../validator/java-package-name.directive.js    |   31 -
 .../java-package-specified.directive.js         |   34 -
 .../form/validator/property-unique.directive.js |   47 -
 .../property-value-specified.directive.js       |   31 -
 .../modules/form/validator/unique.directive.js  |   49 -
 .../getting-started/GettingStarted.provider.js  |  112 -
 .../src/main/js/app/modules/loading/loading.css |   73 -
 .../js/app/modules/loading/loading.directive.js |   51 -
 .../main/js/app/modules/loading/loading.jade    |   23 -
 .../js/app/modules/loading/loading.module.js    |   26 -
 .../js/app/modules/loading/loading.service.js   |   48 -
 .../js/app/modules/navbar/Navbar.provider.js    |   28 -
 .../js/app/modules/navbar/Userbar.provider.js   |   28 -
 .../js/app/modules/navbar/navbar.directive.js   |   30 -
 .../main/js/app/modules/navbar/navbar.module.js |   33 -
 .../js/app/modules/navbar/userbar.directive.js  |   48 -
 .../query-notebooks/query-notebooks.module.js   |  115 -
 .../src/main/js/app/modules/socket.module.js    |   41 -
 .../main/js/app/modules/states/admin.state.js   |   34 -
 .../app/modules/states/configuration.state.js   |  226 --
 .../caches/concurrency.directive.js             |   27 -
 .../configuration/caches/concurrency.jade       |   65 -
 .../configuration/caches/general.directive.js   |   27 -
 .../states/configuration/caches/general.jade    |   65 -
 .../configuration/caches/memory.directive.js    |   27 -
 .../states/configuration/caches/memory.jade     |   88 -
 .../configuration/caches/query.directive.js     |   27 -
 .../states/configuration/caches/query.jade      |   93 -
 .../configuration/caches/rebalance.directive.js |   27 -
 .../states/configuration/caches/rebalance.jade  |   65 -
 .../caches/server-near-cache.directive.js       |   27 -
 .../configuration/caches/server-near-cache.jade |   45 -
 .../caches/statistics.directive.js              |   27 -
 .../states/configuration/caches/statistics.jade |   37 -
 .../configuration/caches/store.directive.js     |   27 -
 .../states/configuration/caches/store.jade      |  271 --
 .../configuration/clusters/atomic.directive.js  |   27 -
 .../states/configuration/clusters/atomic.jade   |   53 -
 .../clusters/attributes.directive.js            |   27 -
 .../configuration/clusters/attributes.jade      |   58 -
 .../configuration/clusters/binary.directive.js  |   27 -
 .../states/configuration/clusters/binary.jade   |  100 -
 .../clusters/collision.directive.js             |   27 -
 .../configuration/clusters/collision.jade       |   60 -
 .../clusters/collision/custom.directive.js      |   27 -
 .../clusters/collision/custom.jade              |   24 -
 .../clusters/collision/fifo-queue.directive.js  |   27 -
 .../clusters/collision/fifo-queue.jade          |   28 -
 .../collision/job-stealing.directive.js         |   27 -
 .../clusters/collision/job-stealing.jade        |   64 -
 .../collision/priority-queue.directive.js       |   27 -
 .../clusters/collision/priority-queue.jade      |   43 -
 .../clusters/communication.directive.js         |   27 -
 .../configuration/clusters/communication.jade   |   96 -
 .../clusters/connector.directive.js             |   27 -
 .../configuration/clusters/connector.jade       |  103 -
 .../clusters/deployment.directive.js            |   27 -
 .../configuration/clusters/deployment.jade      |  119 -
 .../clusters/discovery.directive.js             |   27 -
 .../configuration/clusters/discovery.jade       |   83 -
 .../configuration/clusters/events.directive.js  |   27 -
 .../states/configuration/clusters/events.jade   |   37 -
 .../clusters/failover.directive.js              |   27 -
 .../states/configuration/clusters/failover.jade |   82 -
 .../configuration/clusters/general.directive.js |   27 -
 .../states/configuration/clusters/general.jade  |   68 -
 .../general/discovery/cloud.directive.js        |   27 -
 .../clusters/general/discovery/cloud.jade       |  127 -
 .../general/discovery/google.directive.js       |   27 -
 .../clusters/general/discovery/google.jade      |   38 -
 .../general/discovery/jdbc.directive.js         |   27 -
 .../clusters/general/discovery/jdbc.jade        |   24 -
 .../general/discovery/multicast.directive.js    |   27 -
 .../clusters/general/discovery/multicast.jade   |  109 -
 .../clusters/general/discovery/s3.directive.js  |   27 -
 .../clusters/general/discovery/s3.jade          |   27 -
 .../general/discovery/shared.directive.js       |   27 -
 .../clusters/general/discovery/shared.jade      |   23 -
 .../clusters/general/discovery/vm.directive.js  |   27 -
 .../clusters/general/discovery/vm.jade          |   90 -
 .../general/discovery/zookeeper.directive.js    |   27 -
 .../clusters/general/discovery/zookeeper.jade   |   74 -
 .../bounded-exponential-backoff.directive.js    |   27 -
 .../bounded-exponential-backoff.jade            |   27 -
 .../zookeeper/retrypolicy/custom.directive.js   |   27 -
 .../discovery/zookeeper/retrypolicy/custom.jade |   24 -
 .../exponential-backoff.directive.js            |   27 -
 .../retrypolicy/exponential-backoff.jade        |   27 -
 .../zookeeper/retrypolicy/forever.directive.js  |   27 -
 .../zookeeper/retrypolicy/forever.jade          |   22 -
 .../zookeeper/retrypolicy/n-times.directive.js  |   27 -
 .../zookeeper/retrypolicy/n-times.jade          |   25 -
 .../zookeeper/retrypolicy/one-time.directive.js |   27 -
 .../zookeeper/retrypolicy/one-time.jade         |   23 -
 .../retrypolicy/until-elapsed.directive.js      |   27 -
 .../zookeeper/retrypolicy/until-elapsed.jade    |   25 -
 .../configuration/clusters/igfs.directive.js    |   27 -
 .../states/configuration/clusters/igfs.jade     |   37 -
 .../configuration/clusters/logger.directive.js  |   27 -
 .../states/configuration/clusters/logger.jade   |   65 -
 .../clusters/logger/custom.directive.js         |   27 -
 .../configuration/clusters/logger/custom.jade   |   24 -
 .../clusters/logger/log4j.directive.js          |   27 -
 .../configuration/clusters/logger/log4j.jade    |   49 -
 .../clusters/logger/log4j2.directive.js         |   27 -
 .../configuration/clusters/logger/log4j2.jade   |   38 -
 .../clusters/marshaller.directive.js            |   27 -
 .../configuration/clusters/marshaller.jade      |   69 -
 .../configuration/clusters/metrics.directive.js |   27 -
 .../states/configuration/clusters/metrics.jade  |   50 -
 .../configuration/clusters/ssl.directive.js     |   27 -
 .../states/configuration/clusters/ssl.jade      |  108 -
 .../configuration/clusters/swap.directive.js    |   27 -
 .../states/configuration/clusters/swap.jade     |   67 -
 .../configuration/clusters/thread.directive.js  |   27 -
 .../states/configuration/clusters/thread.jade   |   48 -
 .../configuration/clusters/time.directive.js    |   27 -
 .../states/configuration/clusters/time.jade     |   47 -
 .../clusters/transactions.directive.js          |   27 -
 .../configuration/clusters/transactions.jade    |   59 -
 .../configuration/domains/general.directive.js  |   27 -
 .../states/configuration/domains/general.jade   |   46 -
 .../configuration/domains/query.directive.js    |   27 -
 .../states/configuration/domains/query.jade     |  169 -
 .../configuration/domains/store.directive.js    |   27 -
 .../states/configuration/domains/store.jade     |  126 -
 .../states/configuration/igfs/dual.directive.js |   27 -
 .../modules/states/configuration/igfs/dual.jade |   42 -
 .../igfs/fragmentizer.directive.js              |   27 -
 .../states/configuration/igfs/fragmentizer.jade |   43 -
 .../configuration/igfs/general.directive.js     |   27 -
 .../states/configuration/igfs/general.jade      |   53 -
 .../states/configuration/igfs/ipc.directive.js  |   27 -
 .../modules/states/configuration/igfs/ipc.jade  |   57 -
 .../states/configuration/igfs/misc.directive.js |   27 -
 .../modules/states/configuration/igfs/misc.jade |  108 -
 .../configuration/igfs/secondary.directive.js   |   27 -
 .../states/configuration/igfs/secondary.jade    |   44 -
 .../configuration/preview-panel.directive.js    |  239 --
 .../summary/summary-tabs.directive.js           |   50 -
 .../configuration/summary/summary.controller.js |  359 --
 .../configuration/summary/summary.resource.js   |   40 -
 .../main/js/app/modules/states/logout.state.js  |   36 -
 .../js/app/modules/states/password.state.js     |   46 -
 .../main/js/app/modules/states/profile.state.js |   34 -
 .../main/js/app/modules/states/signin.state.js  |   53 -
 .../src/main/js/app/modules/states/sql.state.js |   46 -
 .../main/js/app/modules/user/Auth.service.js    |   76 -
 .../main/js/app/modules/user/User.service.js    |   65 -
 .../src/main/js/app/modules/user/user.module.js |   28 -
 .../main/js/app/services/ChartColors.service.js |   22 -
 .../src/main/js/app/services/Clone.service.js   |   64 -
 .../src/main/js/app/services/Confirm.service.js |   70 -
 .../js/app/services/ConfirmBatch.service.js     |   92 -
 .../js/app/services/CopyToClipboard.service.js  |   50 -
 .../main/js/app/services/Countries.service.js   |   31 -
 .../src/main/js/app/services/Focus.service.js   |   33 -
 .../main/js/app/services/InetAddress.service.js |   53 -
 .../main/js/app/services/JavaTypes.service.js   |   84 -
 .../main/js/app/services/LegacyTable.service.js |  205 -
 .../main/js/app/services/LegacyUtils.service.js |  948 -----
 .../main/js/app/services/Messages.service.js    |   63 -
 .../js/app/services/ModelNormalizer.service.js  |   59 -
 .../app/services/UnsavedChangesGuard.service.js |   38 -
 modules/web-console/src/main/js/app/vendor.js   |   54 -
 .../src/main/js/controllers/admin-controller.js |   91 -
 .../main/js/controllers/caches-controller.js    |  470 ---
 .../main/js/controllers/clusters-controller.js  |  626 ----
 .../main/js/controllers/domains-controller.js   | 1746 ---------
 .../src/main/js/controllers/igfs-controller.js  |  401 --
 .../main/js/controllers/profile-controller.js   |   91 -
 .../src/main/js/controllers/sql-controller.js   | 1588 --------
 .../src/main/js/generator/generator-common.js   |  611 ---
 .../src/main/js/generator/generator-java.js     | 3404 -----------------
 .../src/main/js/generator/generator-optional.js |   25 -
 .../main/js/generator/generator-properties.js   |  150 -
 .../src/main/js/generator/generator-readme.js   |   85 -
 .../src/main/js/generator/generator-xml.js      | 1978 ----------
 .../src/main/js/gulpfile.babel.js/index.js      |   26 -
 .../src/main/js/gulpfile.babel.js/paths.js      |   70 -
 .../main/js/gulpfile.babel.js/tasks/build.js    |   21 -
 .../main/js/gulpfile.babel.js/tasks/bundle.js   |   32 -
 .../main/js/gulpfile.babel.js/tasks/clean.js    |   32 -
 .../src/main/js/gulpfile.babel.js/tasks/copy.js |   33 -
 .../gulpfile.babel.js/tasks/ignite-modules.js   |   55 -
 .../src/main/js/gulpfile.babel.js/tasks/jade.js |   40 -
 .../main/js/gulpfile.babel.js/tasks/watch.js    |   31 -
 .../main/js/gulpfile.babel.js/webpack/common.js |  192 -
 .../webpack/environments/development.js         |   64 -
 .../webpack/environments/production.js          |   45 -
 .../main/js/gulpfile.babel.js/webpack/index.js  |   32 -
 .../webpack/plugins/progress.js                 |   82 -
 .../src/main/js/ignite_modules/README.txt       |    6 -
 .../src/main/js/ignite_modules/index.js         |   27 -
 modules/web-console/src/main/js/package.json    |  128 -
 .../web-console/src/main/js/public/favicon.ico  |  Bin 1150 -> 0 bytes
 .../src/main/js/public/images/cache.png         |  Bin 23700 -> 0 bytes
 .../src/main/js/public/images/cluster.png       |  Bin 29376 -> 0 bytes
 .../src/main/js/public/images/docker.png        |  Bin 521 -> 0 bytes
 .../src/main/js/public/images/domains.png       |  Bin 23828 -> 0 bytes
 .../src/main/js/public/images/igfs.png          |  Bin 14307 -> 0 bytes
 .../src/main/js/public/images/ignite-logo.png   |  Bin 1982 -> 0 bytes
 .../main/js/public/images/ignite-logo@2x.png    |  Bin 3325 -> 0 bytes
 .../src/main/js/public/images/ignite-puzzle.png |  Bin 71974 -> 0 bytes
 .../src/main/js/public/images/java.png          |  Bin 170 -> 0 bytes
 .../src/main/js/public/images/pb-ignite.png     |  Bin 3493 -> 0 bytes
 .../src/main/js/public/images/pb-ignite@2x.png  |  Bin 8558 -> 0 bytes
 .../src/main/js/public/images/query-chart.png   |  Bin 16637 -> 0 bytes
 .../main/js/public/images/query-metadata.png    |  Bin 32298 -> 0 bytes
 .../src/main/js/public/images/query-table.png   |  Bin 29189 -> 0 bytes
 .../src/main/js/public/images/summary.png       |  Bin 31997 -> 0 bytes
 .../src/main/js/public/images/xml.png           |  Bin 232 -> 0 bytes
 .../public/stylesheets/_bootstrap-custom.scss   |   65 -
 .../stylesheets/_bootstrap-variables.scss       |  891 -----
 .../stylesheets/_font-awesome-custom.scss       |   32 -
 .../src/main/js/public/stylesheets/style.scss   | 2156 -----------
 .../main/js/public/stylesheets/variables.scss   |   28 -
 modules/web-console/src/main/js/serve.js        |  116 -
 modules/web-console/src/main/js/serve/agent.js  |  714 ----
 .../src/main/js/serve/agent_dists/README.txt    |    7 -
 modules/web-console/src/main/js/serve/app.js    |   42 -
 .../web-console/src/main/js/serve/browser.js    |  378 --
 .../main/js/serve/config/settings.json.sample   |   26 -
 .../web-console/src/main/js/serve/configure.js  |   84 -
 modules/web-console/src/main/js/serve/mail.js   |   75 -
 modules/web-console/src/main/js/serve/mongo.js  |  676 ----
 .../src/main/js/serve/routes/admin.js           |  126 -
 .../src/main/js/serve/routes/agent.js           |   81 -
 .../src/main/js/serve/routes/caches.js          |  132 -
 .../src/main/js/serve/routes/clusters.js        |  146 -
 .../src/main/js/serve/routes/demo.js            |  135 -
 .../src/main/js/serve/routes/demo/caches.json   |   87 -
 .../src/main/js/serve/routes/demo/clusters.json |   50 -
 .../src/main/js/serve/routes/demo/domains.json  |  307 --
 .../src/main/js/serve/routes/demo/igfss.json    |   10 -
 .../src/main/js/serve/routes/domains.js         |  195 -
 .../src/main/js/serve/routes/igfs.js            |  122 -
 .../src/main/js/serve/routes/notebooks.js       |  121 -
 .../src/main/js/serve/routes/profile.js         |  102 -
 .../src/main/js/serve/routes/public.js          |  235 --
 .../src/main/js/serve/routes/routes.js          |  103 -
 .../web-console/src/main/js/serve/settings.js   |   84 -
 modules/web-console/src/main/js/views/base.jade |   22 -
 .../src/main/js/views/configuration/caches.jade |   52 -
 .../main/js/views/configuration/clusters.jade   |   64 -
 .../js/views/configuration/domains-import.jade  |  211 --
 .../main/js/views/configuration/domains.jade    |   66 -
 .../src/main/js/views/configuration/igfs.jade   |   51 -
 .../main/js/views/configuration/sidebar.jade    |   29 -
 .../summary-project-structure.jade              |   27 -
 .../js/views/configuration/summary-tabs.jade    |   25 -
 .../main/js/views/configuration/summary.jade    |  152 -
 .../src/main/js/views/includes/footer.jade      |   23 -
 .../src/main/js/views/includes/header.jade      |   51 -
 .../web-console/src/main/js/views/index.jade    |   48 -
 .../web-console/src/main/js/views/reset.jade    |   48 -
 .../src/main/js/views/settings/admin.jade       |   76 -
 .../src/main/js/views/settings/profile.jade     |   76 -
 .../web-console/src/main/js/views/signin.jade   |  163 -
 .../src/main/js/views/sql/cache-metadata.jade   |   40 -
 .../src/main/js/views/sql/chart-settings.jade   |   40 -
 .../src/main/js/views/sql/notebook-new.jade     |   31 -
 .../src/main/js/views/sql/paragraph-rate.jade   |   31 -
 .../web-console/src/main/js/views/sql/sql.jade  |  201 -
 .../main/js/views/templates/agent-download.jade |   48 -
 .../src/main/js/views/templates/alert.jade      |   21 -
 .../main/js/views/templates/batch-confirm.jade  |   32 -
 .../src/main/js/views/templates/clone.jade      |   31 -
 .../src/main/js/views/templates/confirm.jade    |   31 -
 .../src/main/js/views/templates/demo-info.jade  |   45 -
 .../src/main/js/views/templates/dropdown.jade   |   21 -
 .../js/views/templates/getting-started.jade     |   32 -
 .../src/main/js/views/templates/message.jade    |   26 -
 .../src/main/js/views/templates/pagination.jade |   32 -
 .../src/main/js/views/templates/select.jade     |   26 -
 .../js/views/templates/validation-error.jade    |   25 -
 modules/web-console/src/test/js/routes/agent.js |   94 -
 modules/web-console/web-agent/.gitignore        |    2 +
 modules/web-console/web-agent/README.txt        |   88 +
 .../web-agent/assembly/release-web-agent.xml    |   66 +
 .../web-agent/bin/ignite-web-agent.bat          |   70 +
 .../web-agent/bin/ignite-web-agent.sh           |   87 +
 modules/web-console/web-agent/demo/README.txt   |    4 +
 modules/web-console/web-agent/demo/db-init.sql  |  102 +
 .../web-agent/jdbc-drivers/README.txt           |   10 +
 modules/web-console/web-agent/logs/README.txt   |    5 +
 modules/web-console/web-agent/pom.xml           |  199 +
 .../console/agent/AgentConfiguration.java       |  268 ++
 .../ignite/console/agent/AgentLauncher.java     |  344 ++
 .../apache/ignite/console/agent/AgentUtils.java |  111 +
 .../console/agent/handlers/AbstractHandler.java |  110 +
 .../console/agent/handlers/DatabaseHandler.java |  298 ++
 .../console/agent/handlers/RestHandler.java     |  276 ++
 .../ignite/console/demo/AgentClusterDemo.java   |  641 ++++
 .../ignite/console/demo/AgentMetadataDemo.java  |   92 +
 .../apache/ignite/console/demo/model/Car.java   |  152 +
 .../ignite/console/demo/model/Country.java      |  152 +
 .../ignite/console/demo/model/Department.java   |  152 +
 .../ignite/console/demo/model/Employee.java     |  356 ++
 .../ignite/console/demo/model/Parking.java      |  152 +
 .../src/main/resources/log4j.properties         |   53 +
 pom.xml                                         |    2 +-
 861 files changed, 45011 insertions(+), 41666 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/ignite/blob/39ec7d06/modules/web-console/pom.xml
----------------------------------------------------------------------
diff --cc modules/web-console/pom.xml
index ab258c0,e66252c..18821b4
--- a/modules/web-console/pom.xml
+++ b/modules/web-console/pom.xml
@@@ -31,7 -31,8 +31,8 @@@
      </parent>
  
      <artifactId>ignite-web-console</artifactId>
 -    <version>1.7.0-SNAPSHOT</version>
 +    <version>1.8.0-SNAPSHOT</version>
+     <url>http://ignite.apache.org</url>
  
      <build>
          <plugins>

http://git-wip-us.apache.org/repos/asf/ignite/blob/39ec7d06/modules/web-console/web-agent/pom.xml
----------------------------------------------------------------------
diff --cc modules/web-console/web-agent/pom.xml
index 0000000,530a272..736136a
mode 000000,100644..100644
--- a/modules/web-console/web-agent/pom.xml
+++ b/modules/web-console/web-agent/pom.xml
@@@ -1,0 -1,199 +1,199 @@@
+ <?xml version="1.0" encoding="UTF-8"?>
+ 
+ <!--
+   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.
+ -->
+ 
+ <!--
+     POM file.
+ -->
+ <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+     <modelVersion>4.0.0</modelVersion>
+ 
+     <parent>
+         <groupId>org.apache.ignite</groupId>
+         <artifactId>ignite-parent</artifactId>
+         <version>1</version>
+         <relativePath>../../../parent</relativePath>
+     </parent>
+ 
+     <artifactId>ignite-web-agent</artifactId>
+     <packaging>jar</packaging>
 -    <version>1.7.0-SNAPSHOT</version>
++    <version>1.8.0-SNAPSHOT</version>
+     <url>http://ignite.apache.org</url>
+ 
+     <properties>
+         <maven.build.timestamp.format>yyMMddHHmmss</maven.build.timestamp.format>
+     </properties>
+ 
+     <dependencies>
+         <dependency>
+             <groupId>io.socket</groupId>
+             <artifactId>socket.io-client</artifactId>
+             <version>0.7.0</version>
+         </dependency>
+ 
+         <dependency>
+             <groupId>com.fasterxml.jackson.datatype</groupId>
+             <artifactId>jackson-datatype-json-org</artifactId>
+             <version>${jackson2.version}</version>
+         </dependency>
+ 
+         <dependency>
+             <groupId>com.beust</groupId>
+             <artifactId>jcommander</artifactId>
+             <version>1.48</version>
+         </dependency>
+ 
+         <dependency>
+             <groupId>org.apache.httpcomponents</groupId>
+             <artifactId>httpclient</artifactId>
+             <version>${httpclient.version}</version>
+         </dependency>
+ 
+         <dependency>
+             <groupId>org.apache.ignite</groupId>
+             <artifactId>ignite-schema-import-db</artifactId>
+             <version>${project.version}</version>
+             <exclusions>
+                 <exclusion>
+                     <groupId>org.gridgain</groupId>
+                     <artifactId>ignite-shmem</artifactId>
+                 </exclusion>
+             </exclusions>
+         </dependency>
+ 
+         <dependency>
+             <groupId>org.apache.ignite</groupId>
+             <artifactId>ignite-indexing</artifactId>
+             <version>${project.version}</version>
+         </dependency>
+ 
+         <dependency>
+             <groupId>org.apache.ignite</groupId>
+             <artifactId>ignite-rest-http</artifactId>
+             <version>${project.version}</version>
+         </dependency>
+ 
+         <dependency>
+             <groupId>org.apache.ignite</groupId>
+             <artifactId>ignite-spring</artifactId>
+             <version>${project.version}</version>
+             <exclusions>
+                 <exclusion>
+                     <groupId>org.springframework</groupId>
+                     <artifactId>spring-aop</artifactId>
+                 </exclusion>
+                 <exclusion>
+                     <groupId>org.springframework</groupId>
+                     <artifactId>spring-tx</artifactId>
+                 </exclusion>
+                 <exclusion>
+                     <groupId>org.springframework</groupId>
+                     <artifactId>spring-jdbc</artifactId>
+                 </exclusion>
+             </exclusions>
+         </dependency>
+ 
+         <dependency>
+             <groupId>org.apache.ignite</groupId>
+             <artifactId>ignite-log4j</artifactId>
+             <version>${project.version}</version>
+         </dependency>
+     </dependencies>
+ 
+     <build>
+         <finalName>ignite-web-agent-${project.version}</finalName>
+ 
+         <plugins>
+             <plugin>
+                 <artifactId>maven-jar-plugin</artifactId>
+                 <version>2.5</version>
+ 
+                 <configuration>
+                     <archive>
+                         <manifest>
+                             <mainClass>org.apache.ignite.console.agent.AgentLauncher</mainClass>
+                         </manifest>
+                         <manifestEntries>
+                             <Build-Time>${maven.build.timestamp}</Build-Time>
+                         </manifestEntries>
+                     </archive>
+                 </configuration>
+             </plugin>
+ 
+             <plugin>
+                 <groupId>org.apache.maven.plugins</groupId>
+                 <artifactId>maven-shade-plugin</artifactId>
+                 <version>2.4</version>
+ 
+                 <executions>
+                     <execution>
+                         <phase>package</phase>
+                         <goals>
+                             <goal>shade</goal>
+                         </goals>
+ 
+                         <configuration>
+                             <createDependencyReducedPom>false</createDependencyReducedPom>
+                             <filters>
+                                 <filter>
+                                     <artifact>*:*</artifact>
+                                     <excludes>
+                                         <exclude>META-INF/maven/**</exclude>
+                                     </excludes>
+                                 </filter>
+                             </filters>
+                         </configuration>
+                     </execution>
+                 </executions>
+             </plugin>
+ 
+             <plugin>
+                 <groupId>org.apache.maven.plugins</groupId>
+                 <artifactId>maven-assembly-plugin</artifactId>
+                 <version>2.4</version>
+                 <inherited>false</inherited>
+ 
+                 <executions>
+                     <execution>
+                         <id>release-web-agent</id>
+                         <phase>package</phase>
+                         <goals>
+                             <goal>single</goal>
+                         </goals>
+                         <configuration>
+                             <descriptors>
+                                 <descriptor>assembly/release-web-agent.xml</descriptor>
+                             </descriptors>
+                             <finalName>ignite-web-agent-${project.version}</finalName>
+                             <outputDirectory>target</outputDirectory>
+                             <appendAssemblyId>false</appendAssemblyId>
+                         </configuration>
+                     </execution>
+                 </executions>
+             </plugin>
+ 
+             <plugin>
+                 <groupId>org.apache.maven.plugins</groupId>
+                 <artifactId>maven-deploy-plugin</artifactId>
+                 <configuration>
+                     <skip>true</skip>
+                 </configuration>
+             </plugin>
+         </plugins>
+     </build>
+ </project>

http://git-wip-us.apache.org/repos/asf/ignite/blob/39ec7d06/pom.xml
----------------------------------------------------------------------


[10/52] ignite git commit: Web Console beta-3.

Posted by ak...@apache.org.
http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/src/main/js/controllers/sql-controller.js
----------------------------------------------------------------------
diff --git a/modules/web-console/src/main/js/controllers/sql-controller.js b/modules/web-console/src/main/js/controllers/sql-controller.js
deleted file mode 100644
index 7a851c3..0000000
--- a/modules/web-console/src/main/js/controllers/sql-controller.js
+++ /dev/null
@@ -1,1588 +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.
- */
-
-// Controller for SQL notebook screen.
-export default ['sqlController', [
-    '$rootScope', '$scope', '$http', '$q', '$timeout', '$interval', '$animate', '$location', '$anchorScroll', '$state', '$modal', '$popover', 'IgniteLoading', 'IgniteLegacyUtils', 'IgniteMessages', 'IgniteConfirm', 'IgniteAgentMonitor', 'IgniteChartColors', 'QueryNotebooks', 'uiGridConstants', 'uiGridExporterConstants',
-    function($root, $scope, $http, $q, $timeout, $interval, $animate, $location, $anchorScroll, $state, $modal, $popover, Loading, LegacyUtils, Messages, Confirm, agentMonitor, IgniteChartColors, QueryNotebooks, uiGridConstants, uiGridExporterConstants) {
-        let stopTopology = null;
-
-        const _tryStopRefresh = function(paragraph) {
-            if (paragraph.rate && paragraph.rate.stopTime) {
-                $interval.cancel(paragraph.rate.stopTime);
-
-                delete paragraph.rate.stopTime;
-            }
-        };
-
-        const _stopTopologyRefresh = () => {
-            $interval.cancel(stopTopology);
-
-            if ($scope.notebook && $scope.notebook.paragraphs)
-                $scope.notebook.paragraphs.forEach((paragraph) => _tryStopRefresh(paragraph));
-        };
-
-        $scope.$on('$stateChangeStart', _stopTopologyRefresh);
-
-        $scope.caches = [];
-
-        $scope.pageSizes = [50, 100, 200, 400, 800, 1000];
-
-        $scope.timeLineSpans = ['1', '5', '10', '15', '30'];
-
-        $scope.aggregateFxs = ['FIRST', 'LAST', 'MIN', 'MAX', 'SUM', 'AVG', 'COUNT'];
-
-        $scope.modes = LegacyUtils.mkOptions(['PARTITIONED', 'REPLICATED', 'LOCAL']);
-
-        $scope.loadingText = $root.IgniteDemoMode ? 'Demo grid is starting. Please wait...' : 'Loading notebook screen...';
-
-        $scope.timeUnit = [
-            {value: 1000, label: 'seconds', short: 's'},
-            {value: 60000, label: 'minutes', short: 'm'},
-            {value: 3600000, label: 'hours', short: 'h'}
-        ];
-
-        $scope.exportDropdown = [
-            { text: 'Export all', click: 'exportCsvAll(paragraph)' }
-            // { 'text': 'Export all to CSV', 'click': 'exportCsvAll(paragraph)' },
-            // { 'text': 'Export all to PDF', 'click': 'exportPdfAll(paragraph)' }
-        ];
-
-        $scope.metadata = [];
-
-        $scope.metaFilter = '';
-
-        $scope.metaOptions = {
-            nodeChildren: 'children',
-            dirSelectable: true,
-            injectClasses: {
-                iExpanded: 'fa fa-minus-square-o',
-                iCollapsed: 'fa fa-plus-square-o'
-            }
-        };
-
-        $scope.maskCacheName = (cacheName) => _.isEmpty(cacheName) ? '<default>' : cacheName;
-
-        // Time line X axis descriptor.
-        const TIME_LINE = {value: -1, type: 'java.sql.Date', label: 'TIME_LINE'};
-
-        // Row index X axis descriptor.
-        const ROW_IDX = {value: -2, type: 'java.lang.Integer', label: 'ROW_IDX'};
-
-        // We need max 1800 items to hold history for 30 mins in case of refresh every second.
-        const HISTORY_LENGTH = 1800;
-
-        const MAX_VAL_COLS = IgniteChartColors.length;
-
-        $anchorScroll.yOffset = 55;
-
-        $scope.chartColor = function(index) {
-            return {color: 'white', 'background-color': IgniteChartColors[index]};
-        };
-
-        function _chartNumber(arr, idx, dflt) {
-            if (idx >= 0 && arr && arr.length > idx && _.isNumber(arr[idx]))
-                return arr[idx];
-
-            return dflt;
-        }
-
-        function _min(rows, idx, dflt) {
-            let min = _chartNumber(rows[0], idx, dflt);
-
-            _.forEach(rows, (row) => {
-                const v = _chartNumber(row, idx, dflt);
-
-                if (v < min)
-                    min = v;
-            });
-
-            return min;
-        }
-
-        function _max(rows, idx, dflt) {
-            let max = _chartNumber(rows[0], idx, dflt);
-
-            _.forEach(rows, (row) => {
-                const v = _chartNumber(row, idx, dflt);
-
-                if (v > max)
-                    max = v;
-            });
-
-            return max;
-        }
-
-        function _sum(rows, idx) {
-            let sum = 0;
-
-            _.forEach(rows, (row) => sum += _chartNumber(row, idx, 0));
-
-            return sum;
-        }
-
-        function _aggregate(rows, aggFx, idx, dflt) {
-            const len = rows.length;
-
-            switch (aggFx) {
-                case 'FIRST':
-                    return _chartNumber(rows[0], idx, dflt);
-
-                case 'LAST':
-                    return _chartNumber(rows[len - 1], idx, dflt);
-
-                case 'MIN':
-                    return _min(rows, idx, dflt);
-
-                case 'MAX':
-                    return _max(rows, idx, dflt);
-
-                case 'SUM':
-                    return _sum(rows, idx);
-
-                case 'AVG':
-                    return len > 0 ? _sum(rows, idx) / len : 0;
-
-                case 'COUNT':
-                    return len;
-
-                default:
-            }
-
-            return 0;
-        }
-
-        function _chartLabel(arr, idx, dflt) {
-            if (arr && arr.length > idx && _.isString(arr[idx]))
-                return arr[idx];
-
-            return dflt;
-        }
-
-        function _chartDatum(paragraph) {
-            let datum = [];
-
-            if (paragraph.chartColumnsConfigured()) {
-                paragraph.chartValCols.forEach(function(valCol) {
-                    let index = 0;
-                    let values = [];
-                    const colIdx = valCol.value;
-
-                    if (paragraph.chartTimeLineEnabled()) {
-                        const aggFx = valCol.aggFx;
-                        const colLbl = valCol.label + ' [' + aggFx + ']';
-
-                        if (paragraph.charts && paragraph.charts.length === 1)
-                            datum = paragraph.charts[0].data;
-
-                        const chartData = _.find(datum, {series: valCol.label});
-
-                        const leftBound = new Date();
-                        leftBound.setMinutes(leftBound.getMinutes() - parseInt(paragraph.timeLineSpan, 10));
-
-                        if (chartData) {
-                            const lastItem = _.last(paragraph.chartHistory);
-
-                            values = chartData.values;
-
-                            values.push({
-                                x: lastItem.tm,
-                                y: _aggregate(lastItem.rows, aggFx, colIdx, index++)
-                            });
-
-                            while (values.length > 0 && values[0].x < leftBound)
-                                values.shift();
-                        }
-                        else {
-                            _.forEach(paragraph.chartHistory, (history) => {
-                                if (history.tm >= leftBound) {
-                                    values.push({
-                                        x: history.tm,
-                                        y: _aggregate(history.rows, aggFx, colIdx, index++)
-                                    });
-                                }
-                            });
-
-                            datum.push({series: valCol.label, key: colLbl, values});
-                        }
-                    }
-                    else {
-                        index = paragraph.total;
-
-                        values = _.map(paragraph.rows, function(row) {
-                            const xCol = paragraph.chartKeyCols[0].value;
-
-                            const v = {
-                                x: _chartNumber(row, xCol, index),
-                                xLbl: _chartLabel(row, xCol, null),
-                                y: _chartNumber(row, colIdx, index)
-                            };
-
-                            index++;
-
-                            return v;
-                        });
-
-                        datum.push({series: valCol.label, key: valCol.label, values});
-                    }
-                });
-            }
-
-            return datum;
-        }
-
-        function _xX(d) {
-            return d.x;
-        }
-
-        function _yY(d) {
-            return d.y;
-        }
-
-        function _xAxisTimeFormat(d) {
-            return d3.time.format('%X')(new Date(d));
-        }
-
-        const _intClasses = ['java.lang.Byte', 'java.lang.Integer', 'java.lang.Long', 'java.lang.Short'];
-
-        function _intType(cls) {
-            return _.includes(_intClasses, cls);
-        }
-
-        const _xAxisWithLabelFormat = function(paragraph) {
-            return function(d) {
-                const values = paragraph.charts[0].data[0].values;
-
-                const fmt = _intType(paragraph.chartKeyCols[0].type) ? 'd' : ',.2f';
-
-                const dx = values[d];
-
-                if (!dx)
-                    return d3.format(fmt)(d);
-
-                const lbl = dx.xLbl;
-
-                return lbl ? lbl : d3.format(fmt)(d);
-            };
-        };
-
-        function _xAxisLabel(paragraph) {
-            return _.isEmpty(paragraph.chartKeyCols) ? 'X' : paragraph.chartKeyCols[0].label;
-        }
-
-        const _yAxisFormat = function(d) {
-            const fmt = d < 1000 ? ',.2f' : '.3s';
-
-            return d3.format(fmt)(d);
-        };
-
-        function _updateCharts(paragraph) {
-            $timeout(() => _.forEach(paragraph.charts, (chart) => chart.api.update()), 100);
-        }
-
-        function _updateChartsWithData(paragraph, newDatum) {
-            $timeout(() => {
-                if (!paragraph.chartTimeLineEnabled()) {
-                    const chartDatum = paragraph.charts[0].data;
-
-                    chartDatum.length = 0;
-
-                    _.forEach(newDatum, (series) => chartDatum.push(series));
-                }
-
-                paragraph.charts[0].api.update();
-            });
-        }
-
-        function _yAxisLabel(paragraph) {
-            const cols = paragraph.chartValCols;
-
-            const tml = paragraph.chartTimeLineEnabled();
-
-            return _.isEmpty(cols) ? 'Y' : _.map(cols, function(col) {
-                let lbl = col.label;
-
-                if (tml)
-                    lbl += ' [' + col.aggFx + ']';
-
-                return lbl;
-            }).join(', ');
-        }
-
-        function _barChart(paragraph) {
-            const datum = _chartDatum(paragraph);
-
-            if (_.isEmpty(paragraph.charts)) {
-                const stacked = paragraph.chartsOptions && paragraph.chartsOptions.barChart
-                    ? paragraph.chartsOptions.barChart.stacked
-                    : true;
-
-                const options = {
-                    chart: {
-                        type: 'multiBarChart',
-                        height: 400,
-                        margin: {left: 70},
-                        duration: 0,
-                        x: _xX,
-                        y: _yY,
-                        xAxis: {
-                            axisLabel: _xAxisLabel(paragraph),
-                            tickFormat: paragraph.chartTimeLineEnabled() ? _xAxisTimeFormat : _xAxisWithLabelFormat(paragraph),
-                            showMaxMin: false
-                        },
-                        yAxis: {
-                            axisLabel: _yAxisLabel(paragraph),
-                            tickFormat: _yAxisFormat
-                        },
-                        color: IgniteChartColors,
-                        stacked,
-                        showControls: true,
-                        legend: {
-                            vers: 'furious',
-                            margin: {right: -25}
-                        }
-                    }
-                };
-
-                paragraph.charts = [{options, data: datum}];
-
-                _updateCharts(paragraph);
-            }
-            else
-                _updateChartsWithData(paragraph, datum);
-        }
-
-        function _pieChartDatum(paragraph) {
-            const datum = [];
-
-            if (paragraph.chartColumnsConfigured() && !paragraph.chartTimeLineEnabled()) {
-                paragraph.chartValCols.forEach(function(valCol) {
-                    let index = paragraph.total;
-
-                    const values = _.map(paragraph.rows, (row) => {
-                        const xCol = paragraph.chartKeyCols[0].value;
-
-                        const v = {
-                            x: xCol < 0 ? index : row[xCol],
-                            y: _chartNumber(row, valCol.value, index)
-                        };
-
-                        // Workaround for known problem with zero values on Pie chart.
-                        if (v.y === 0)
-                            v.y = 0.0001;
-
-                        index++;
-
-                        return v;
-                    });
-
-                    datum.push({series: paragraph.chartKeyCols[0].label, key: valCol.label, values});
-                });
-            }
-
-            return datum;
-        }
-
-        function _pieChart(paragraph) {
-            let datum = _pieChartDatum(paragraph);
-
-            if (datum.length === 0)
-                datum = [{values: []}];
-
-            paragraph.charts = _.map(datum, function(data) {
-                return {
-                    options: {
-                        chart: {
-                            type: 'pieChart',
-                            height: 400,
-                            duration: 0,
-                            x: _xX,
-                            y: _yY,
-                            showLabels: true,
-                            labelThreshold: 0.05,
-                            labelType: 'percent',
-                            donut: true,
-                            donutRatio: 0.35,
-                            legend: {
-                                vers: 'furious',
-                                margin: {
-                                    right: -25
-                                }
-                            }
-                        },
-                        title: {
-                            enable: true,
-                            text: data.key
-                        }
-                    },
-                    data: data.values
-                };
-            });
-
-            _updateCharts(paragraph);
-        }
-
-        function _lineChart(paragraph) {
-            const datum = _chartDatum(paragraph);
-
-            if (_.isEmpty(paragraph.charts)) {
-                const options = {
-                    chart: {
-                        type: 'lineChart',
-                        height: 400,
-                        margin: { left: 70 },
-                        duration: 0,
-                        x: _xX,
-                        y: _yY,
-                        xAxis: {
-                            axisLabel: _xAxisLabel(paragraph),
-                            tickFormat: paragraph.chartTimeLineEnabled() ? _xAxisTimeFormat : _xAxisWithLabelFormat(paragraph),
-                            showMaxMin: false
-                        },
-                        yAxis: {
-                            axisLabel: _yAxisLabel(paragraph),
-                            tickFormat: _yAxisFormat
-                        },
-                        color: IgniteChartColors,
-                        useInteractiveGuideline: true,
-                        legend: {
-                            vers: 'furious',
-                            margin: {
-                                right: -25
-                            }
-                        }
-                    }
-                };
-
-                paragraph.charts = [{options, data: datum}];
-
-                _updateCharts(paragraph);
-            }
-            else
-                _updateChartsWithData(paragraph, datum);
-        }
-
-        function _areaChart(paragraph) {
-            const datum = _chartDatum(paragraph);
-
-            if (_.isEmpty(paragraph.charts)) {
-                const style = paragraph.chartsOptions && paragraph.chartsOptions.areaChart
-                    ? paragraph.chartsOptions.areaChart.style
-                    : 'stack';
-
-                const options = {
-                    chart: {
-                        type: 'stackedAreaChart',
-                        height: 400,
-                        margin: {left: 70},
-                        duration: 0,
-                        x: _xX,
-                        y: _yY,
-                        xAxis: {
-                            axisLabel: _xAxisLabel(paragraph),
-                            tickFormat: paragraph.chartTimeLineEnabled() ? _xAxisTimeFormat : _xAxisWithLabelFormat(paragraph),
-                            showMaxMin: false
-                        },
-                        yAxis: {
-                            axisLabel: _yAxisLabel(paragraph),
-                            tickFormat: _yAxisFormat
-                        },
-                        color: IgniteChartColors,
-                        style,
-                        legend: {
-                            vers: 'furious',
-                            margin: {right: -25}
-                        }
-                    }
-                };
-
-                paragraph.charts = [{options, data: datum}];
-
-                _updateCharts(paragraph);
-            }
-            else
-                _updateChartsWithData(paragraph, datum);
-        }
-
-        function _chartApplySettings(paragraph, resetCharts) {
-            if (resetCharts)
-                paragraph.charts = [];
-
-            if (paragraph.chart() && paragraph.nonEmpty()) {
-                switch (paragraph.result) {
-                    case 'bar':
-                        _barChart(paragraph);
-                        break;
-
-                    case 'pie':
-                        _pieChart(paragraph);
-                        break;
-
-                    case 'line':
-                        _lineChart(paragraph);
-                        break;
-
-                    case 'area':
-                        _areaChart(paragraph);
-                        break;
-
-                    default:
-                }
-            }
-        }
-
-        $scope.chartRemoveKeyColumn = function(paragraph, index) {
-            paragraph.chartKeyCols.splice(index, 1);
-
-            _chartApplySettings(paragraph, true);
-        };
-
-        $scope.chartRemoveValColumn = function(paragraph, index) {
-            paragraph.chartValCols.splice(index, 1);
-
-            _chartApplySettings(paragraph, true);
-        };
-
-        $scope.chartAcceptKeyColumn = function(paragraph, item) {
-            const accepted = _.findIndex(paragraph.chartKeyCols, item) < 0;
-
-            if (accepted) {
-                paragraph.chartKeyCols = [item];
-
-                _chartApplySettings(paragraph, true);
-            }
-
-            return false;
-        };
-
-        const _numberClasses = ['java.math.BigDecimal', 'java.lang.Byte', 'java.lang.Double',
-            'java.lang.Float', 'java.lang.Integer', 'java.lang.Long', 'java.lang.Short'];
-
-        const _numberType = function(cls) {
-            return _.includes(_numberClasses, cls);
-        };
-
-        $scope.chartAcceptValColumn = function(paragraph, item) {
-            const valCols = paragraph.chartValCols;
-
-            const accepted = _.findIndex(valCols, item) < 0 && item.value >= 0 && _numberType(item.type);
-
-            if (accepted) {
-                if (valCols.length === MAX_VAL_COLS - 1)
-                    valCols.shift();
-
-                valCols.push(item);
-
-                _chartApplySettings(paragraph, true);
-            }
-
-            return false;
-        };
-
-        $scope.scrollParagraphs = [];
-
-        $scope.rebuildScrollParagraphs = function() {
-            $scope.scrollParagraphs = $scope.notebook.paragraphs.map(function(paragraph) {
-                return {
-                    text: paragraph.name,
-                    click: 'scrollToParagraph("' + paragraph.id + '")'
-                };
-            });
-        };
-
-        $scope.scrollToParagraph = function(paragraphId) {
-            const idx = _.findIndex($scope.notebook.paragraphs, {id: paragraphId});
-
-            if (idx >= 0) {
-                if (!_.includes($scope.notebook.expandedParagraphs, idx))
-                    $scope.notebook.expandedParagraphs.push(idx);
-
-                setTimeout(function() {
-                    $scope.notebook.paragraphs[idx].ace.focus();
-                });
-            }
-
-            $location.hash(paragraphId);
-
-            $anchorScroll();
-        };
-
-        const _hideColumn = (col) => col.fieldName !== '_KEY' && col.fieldName !== '_VAL';
-
-        const _allColumn = () => true;
-
-        let paragraphId = 0;
-
-        const _fullColName = function(col) {
-            const res = [];
-
-            if (col.schemaName)
-                res.push(col.schemaName);
-
-            if (col.typeName)
-                res.push(col.typeName);
-
-            res.push(col.fieldName);
-
-            return res.join('.');
-        };
-
-        function enhanceParagraph(paragraph) {
-            paragraph.nonEmpty = function() {
-                return this.rows && this.rows.length > 0;
-            };
-
-            paragraph.chart = function() {
-                return this.result !== 'table' && this.result !== 'none';
-            };
-
-            paragraph.queryExecuted = () =>
-                paragraph.queryArgs && paragraph.queryArgs.query && !paragraph.queryArgs.query.startsWith('EXPLAIN ');
-
-            paragraph.table = function() {
-                return this.result === 'table';
-            };
-
-            paragraph.chartColumnsConfigured = function() {
-                return !_.isEmpty(this.chartKeyCols) && !_.isEmpty(this.chartValCols);
-            };
-
-            paragraph.chartTimeLineEnabled = function() {
-                return !_.isEmpty(this.chartKeyCols) && angular.equals(this.chartKeyCols[0], TIME_LINE);
-            };
-
-            paragraph.timeLineSupported = function() {
-                return this.result !== 'pie';
-            };
-
-            paragraph.refreshExecuting = function() {
-                return paragraph.rate && paragraph.rate.stopTime;
-            };
-
-            Object.defineProperty(paragraph, 'gridOptions', { value: {
-                enableGridMenu: false,
-                enableColumnMenus: false,
-                flatEntityAccess: true,
-                fastWatch: true,
-                updateColumns(cols) {
-                    this.columnDefs = _.map(cols, (col) => {
-                        return {
-                            displayName: col.fieldName,
-                            headerTooltip: _fullColName(col),
-                            field: col.field,
-                            minWidth: 50,
-                            cellClass: 'cell-left'
-                        };
-                    });
-
-                    $timeout(() => this.api.core.notifyDataChange(uiGridConstants.dataChange.COLUMN));
-                },
-                updateRows(rows) {
-                    const sizeChanged = this.data.length !== rows.length;
-
-                    this.data = rows;
-
-                    if (sizeChanged) {
-                        const height = Math.min(rows.length, 15) * 30 + 47;
-
-                        // Remove header height.
-                        this.api.grid.element.css('height', height + 'px');
-
-                        $timeout(() => this.api.core.handleWindowResize());
-                    }
-                },
-                onRegisterApi(api) {
-                    $animate.enabled(api.grid.element, false);
-
-                    this.api = api;
-                }
-            }});
-
-            Object.defineProperty(paragraph, 'chartHistory', {value: []});
-        }
-
-        $scope.aceInit = function(paragraph) {
-            return function(editor) {
-                editor.setAutoScrollEditorIntoView(true);
-                editor.$blockScrolling = Infinity;
-
-                const renderer = editor.renderer;
-
-                renderer.setHighlightGutterLine(false);
-                renderer.setShowPrintMargin(false);
-                renderer.setOption('fontFamily', 'monospace');
-                renderer.setOption('fontSize', '14px');
-                renderer.setOption('minLines', '5');
-                renderer.setOption('maxLines', '15');
-
-                editor.setTheme('ace/theme/chrome');
-
-                Object.defineProperty(paragraph, 'ace', { value: editor });
-            };
-        };
-
-        const _setActiveCache = function() {
-            if ($scope.caches.length > 0) {
-                _.forEach($scope.notebook.paragraphs, (paragraph) => {
-                    if (!_.find($scope.caches, {name: paragraph.cacheName}))
-                        paragraph.cacheName = $scope.caches[0].name;
-                });
-            }
-        };
-
-        const _updateTopology = () =>
-            agentMonitor.topology()
-                .then((clusters) => {
-                    agentMonitor.checkModal();
-
-                    const caches = _.flattenDeep(clusters.map((cluster) => cluster.caches));
-
-                    $scope.caches = _.sortBy(_.map(_.uniqBy(_.reject(caches, {mode: 'LOCAL'}), 'name'), (cache) => {
-                        cache.label = $scope.maskCacheName(cache.name);
-
-                        return cache;
-                    }), 'label');
-
-                    _setActiveCache();
-                })
-                .catch((err) => {
-                    if (err.code === 2)
-                        return agentMonitor.showNodeError('Agent is failed to authenticate in grid. Please check agent\'s login and password.');
-
-                    agentMonitor.showNodeError(err);
-                });
-
-        const _startTopologyRefresh = () => {
-            Loading.start('sqlLoading');
-
-            agentMonitor.awaitAgent()
-                .then(_updateTopology)
-                .finally(() => {
-                    if ($root.IgniteDemoMode)
-                        _.forEach($scope.notebook.paragraphs, $scope.execute);
-
-                    Loading.finish('sqlLoading');
-
-                    stopTopology = $interval(_updateTopology, 5000, 0, false);
-                });
-        };
-
-        const loadNotebook = function(notebook) {
-            $scope.notebook = notebook;
-
-            $scope.notebook_name = notebook.name;
-
-            if (!$scope.notebook.expandedParagraphs)
-                $scope.notebook.expandedParagraphs = [];
-
-            if (!$scope.notebook.paragraphs)
-                $scope.notebook.paragraphs = [];
-
-            _.forEach(notebook.paragraphs, (paragraph) => {
-                paragraph.id = 'paragraph-' + paragraphId++;
-
-                enhanceParagraph(paragraph);
-            });
-
-            if (!notebook.paragraphs || notebook.paragraphs.length === 0)
-                $scope.addParagraph();
-            else
-                $scope.rebuildScrollParagraphs();
-
-            agentMonitor.startWatch({
-                state: 'base.configuration.clusters',
-                text: 'Back to Configuration',
-                goal: 'execute sql statements',
-                onDisconnect: () => {
-                    _stopTopologyRefresh();
-
-                    _startTopologyRefresh();
-                }
-            })
-            .then(_startTopologyRefresh);
-        };
-
-        QueryNotebooks.read($state.params.noteId)
-            .then(loadNotebook)
-            .catch(() => {
-                $scope.notebookLoadFailed = true;
-
-                Loading.finish('sqlLoading');
-            });
-
-        $scope.renameNotebook = function(name) {
-            if (!name)
-                return;
-
-            if ($scope.notebook.name !== name) {
-                const prevName = $scope.notebook.name;
-
-                $scope.notebook.name = name;
-
-                QueryNotebooks.save($scope.notebook)
-                    .then(function() {
-                        const idx = _.findIndex($root.notebooks, function(item) {
-                            return item._id === $scope.notebook._id;
-                        });
-
-                        if (idx >= 0) {
-                            $root.notebooks[idx].name = name;
-
-                            $root.rebuildDropdown();
-                        }
-
-                        $scope.notebook.edit = false;
-                    })
-                    .catch((err) => {
-                        $scope.notebook.name = prevName;
-
-                        Messages.showError(err);
-                    });
-            }
-            else
-                $scope.notebook.edit = false;
-        };
-
-        $scope.removeNotebook = function() {
-            Confirm.confirm('Are you sure you want to remove: "' + $scope.notebook.name + '"?')
-                .then(function() {
-                    return QueryNotebooks.remove($scope.notebook);
-                })
-                .then(function(notebook) {
-                    if (notebook)
-                        $state.go('base.sql.notebook', {noteId: notebook._id});
-                    else
-                        $state.go('base.configuration.clusters');
-                })
-                .catch(Messages.showError);
-        };
-
-        $scope.renameParagraph = function(paragraph, newName) {
-            if (!newName)
-                return;
-
-            if (paragraph.name !== newName) {
-                paragraph.name = newName;
-
-                $scope.rebuildScrollParagraphs();
-
-                QueryNotebooks.save($scope.notebook)
-                    .then(() => paragraph.edit = false)
-                    .catch(Messages.showError);
-            }
-            else
-                paragraph.edit = false;
-        };
-
-        $scope.addParagraph = function() {
-            const sz = $scope.notebook.paragraphs.length;
-
-            const paragraph = {
-                id: 'paragraph-' + paragraphId++,
-                name: 'Query' + (sz === 0 ? '' : sz),
-                query: '',
-                pageSize: $scope.pageSizes[0],
-                timeLineSpan: $scope.timeLineSpans[0],
-                result: 'none',
-                rate: {
-                    value: 1,
-                    unit: 60000,
-                    installed: false
-                }
-            };
-
-            enhanceParagraph(paragraph);
-
-            if ($scope.caches && $scope.caches.length > 0)
-                paragraph.cacheName = $scope.caches[0].name;
-
-            $scope.notebook.paragraphs.push(paragraph);
-
-            $scope.notebook.expandedParagraphs.push(sz);
-
-            $scope.rebuildScrollParagraphs();
-
-            $location.hash(paragraph.id);
-
-            $anchorScroll();
-
-            setTimeout(function() {
-                paragraph.ace.focus();
-            });
-        };
-
-        function _saveChartSettings(paragraph) {
-            if (!_.isEmpty(paragraph.charts)) {
-                const chart = paragraph.charts[0].api.getScope().chart;
-
-                if (!LegacyUtils.isDefined(paragraph.chartsOptions))
-                    paragraph.chartsOptions = {barChart: {stacked: true}, areaChart: {style: 'stack'}};
-
-                switch (paragraph.result) {
-                    case 'bar':
-                        paragraph.chartsOptions.barChart.stacked = chart.stacked();
-
-                        break;
-
-                    case 'area':
-                        paragraph.chartsOptions.areaChart.style = chart.style();
-
-                        break;
-
-                    default:
-                }
-            }
-        }
-
-        $scope.setResult = function(paragraph, new_result) {
-            if (paragraph.result === new_result)
-                return;
-
-            _saveChartSettings(paragraph);
-
-            paragraph.result = new_result;
-
-            if (paragraph.chart())
-                _chartApplySettings(paragraph, true);
-            else
-                $timeout(() => paragraph.gridOptions.api.core.handleWindowResize());
-        };
-
-        $scope.resultEq = function(paragraph, result) {
-            return (paragraph.result === result);
-        };
-
-        $scope.removeParagraph = function(paragraph) {
-            Confirm.confirm('Are you sure you want to remove: "' + paragraph.name + '"?')
-                .then(function() {
-                    $scope.stopRefresh(paragraph);
-
-                    const paragraph_idx = _.findIndex($scope.notebook.paragraphs, function(item) {
-                        return paragraph === item;
-                    });
-
-                    const panel_idx = _.findIndex($scope.expandedParagraphs, function(item) {
-                        return paragraph_idx === item;
-                    });
-
-                    if (panel_idx >= 0)
-                        $scope.expandedParagraphs.splice(panel_idx, 1);
-
-                    $scope.notebook.paragraphs.splice(paragraph_idx, 1);
-
-                    $scope.rebuildScrollParagraphs();
-
-                    QueryNotebooks.save($scope.notebook)
-                        .catch(Messages.showError);
-                });
-        };
-
-        $scope.paragraphExpanded = function(paragraph) {
-            const paragraph_idx = _.findIndex($scope.notebook.paragraphs, function(item) {
-                return paragraph === item;
-            });
-
-            const panel_idx = _.findIndex($scope.notebook.expandedParagraphs, function(item) {
-                return paragraph_idx === item;
-            });
-
-            return panel_idx >= 0;
-        };
-
-        const _columnFilter = function(paragraph) {
-            return paragraph.disabledSystemColumns || paragraph.systemColumns ? _allColumn : _hideColumn;
-        };
-
-        const _notObjectType = function(cls) {
-            return LegacyUtils.isJavaBuiltInClass(cls);
-        };
-
-        function _retainColumns(allCols, curCols, acceptableType, xAxis, unwantedCols) {
-            const retainedCols = [];
-
-            const availableCols = xAxis ? allCols : _.filter(allCols, function(col) {
-                return col.value >= 0;
-            });
-
-            if (availableCols.length > 0) {
-                curCols.forEach(function(curCol) {
-                    const col = _.find(availableCols, {label: curCol.label});
-
-                    if (col && acceptableType(col.type)) {
-                        col.aggFx = curCol.aggFx;
-
-                        retainedCols.push(col);
-                    }
-                });
-
-                // If nothing was restored, add first acceptable column.
-                if (_.isEmpty(retainedCols)) {
-                    let col;
-
-                    if (unwantedCols)
-                        col = _.find(availableCols, (avCol) => !_.find(unwantedCols, {label: avCol.label}) && acceptableType(avCol.type));
-
-                    if (!col)
-                        col = _.find(availableCols, (avCol) => acceptableType(avCol.type));
-
-                    if (col)
-                        retainedCols.push(col);
-                }
-            }
-
-            return retainedCols;
-        }
-
-        const _rebuildColumns = function(paragraph) {
-            _.forEach(_.groupBy(paragraph.meta, 'fieldName'), function(colsByName, fieldName) {
-                const colsByTypes = _.groupBy(colsByName, 'typeName');
-
-                const needType = _.keys(colsByTypes).length > 1;
-
-                _.forEach(colsByTypes, function(colsByType, typeName) {
-                    _.forEach(colsByType, function(col, ix) {
-                        col.fieldName = (needType && !LegacyUtils.isEmptyString(typeName) ? typeName + '.' : '') + fieldName + (ix > 0 ? ix : '');
-                    });
-                });
-            });
-
-            const cols = [];
-
-            _.forEach(paragraph.meta, (col, idx) => {
-                if (paragraph.columnFilter(col)) {
-                    col.field = paragraph.queryArgs.query ? idx.toString() : col.fieldName;
-
-                    cols.push(col);
-                }
-            });
-
-            paragraph.gridOptions.updateColumns(cols);
-
-            paragraph.chartColumns = _.reduce(cols, (acc, col) => {
-                if (_notObjectType(col.fieldTypeName)) {
-                    acc.push({
-                        label: col.fieldName,
-                        type: col.fieldTypeName,
-                        aggFx: $scope.aggregateFxs[0],
-                        value: col.field
-                    });
-                }
-
-                return acc;
-            }, []);
-
-            if (paragraph.chartColumns.length > 0) {
-                paragraph.chartColumns.push(TIME_LINE);
-                paragraph.chartColumns.push(ROW_IDX);
-            }
-
-            // We could accept onl not object columns for X axis.
-            paragraph.chartKeyCols = _retainColumns(paragraph.chartColumns, paragraph.chartKeyCols, _notObjectType, true);
-
-            // We could accept only numeric columns for Y axis.
-            paragraph.chartValCols = _retainColumns(paragraph.chartColumns, paragraph.chartValCols, _numberType, false, paragraph.chartKeyCols);
-        };
-
-        $scope.toggleSystemColumns = function(paragraph) {
-            if (paragraph.disabledSystemColumns)
-                return;
-
-            paragraph.systemColumns = !paragraph.systemColumns;
-
-            paragraph.columnFilter = _columnFilter(paragraph);
-
-            paragraph.chartColumns = [];
-
-            _rebuildColumns(paragraph);
-        };
-
-        const _showLoading = (paragraph, enable) => paragraph.loading = enable;
-
-        /**
-         * @param {Object} paragraph Query
-         * @param {{fieldsMetadata: Array, items: Array, queryId: int, last: Boolean}} res Query results.
-         * @private
-         */
-        const _processQueryResult = function(paragraph, res) {
-            const prevKeyCols = paragraph.chartKeyCols;
-            const prevValCols = paragraph.chartValCols;
-
-            if (!_.eq(paragraph.meta, res.fieldsMetadata)) {
-                paragraph.meta = [];
-
-                paragraph.chartColumns = [];
-
-                if (!LegacyUtils.isDefined(paragraph.chartKeyCols))
-                    paragraph.chartKeyCols = [];
-
-                if (!LegacyUtils.isDefined(paragraph.chartValCols))
-                    paragraph.chartValCols = [];
-
-                if (res.fieldsMetadata.length <= 2) {
-                    const _key = _.find(res.fieldsMetadata, {fieldName: '_KEY'});
-                    const _val = _.find(res.fieldsMetadata, {fieldName: '_VAL'});
-
-                    paragraph.disabledSystemColumns = (res.fieldsMetadata.length === 2 && _key && _val) ||
-                        (res.fieldsMetadata.length === 1 && (_key || _val));
-                }
-
-                paragraph.columnFilter = _columnFilter(paragraph);
-
-                paragraph.meta = res.fieldsMetadata;
-
-                _rebuildColumns(paragraph);
-            }
-
-            paragraph.page = 1;
-
-            paragraph.total = 0;
-
-            paragraph.queryId = res.last ? null : res.queryId;
-
-            delete paragraph.errMsg;
-
-            // Prepare explain results for display in table.
-            if (paragraph.queryArgs.query && paragraph.queryArgs.query.startsWith('EXPLAIN') && res.items) {
-                paragraph.rows = [];
-
-                res.items.forEach(function(row, i) {
-                    const line = res.items.length - 1 === i ? row[0] : row[0] + '\n';
-
-                    line.replace(/\"/g, '').split('\n').forEach((ln) => paragraph.rows.push([ln]));
-                });
-            }
-            else
-                paragraph.rows = res.items;
-
-            paragraph.gridOptions.updateRows(paragraph.rows);
-
-            const chartHistory = paragraph.chartHistory;
-
-            // Clear history on query change.
-            const queryChanged = paragraph.prevQuery !== paragraph.query;
-
-            if (queryChanged) {
-                paragraph.prevQuery = paragraph.query;
-
-                chartHistory.length = 0;
-
-                _.forEach(paragraph.charts, (chart) => chart.data.length = 0);
-            }
-
-            // Add results to history.
-            chartHistory.push({tm: new Date(), rows: paragraph.rows});
-
-            // Keep history size no more than max length.
-            while (chartHistory.length > HISTORY_LENGTH)
-                chartHistory.shift();
-
-            _showLoading(paragraph, false);
-
-            if (paragraph.result === 'none' || !paragraph.queryExecuted())
-                paragraph.result = 'table';
-            else if (paragraph.chart()) {
-                let resetCharts = queryChanged;
-
-                if (!resetCharts) {
-                    const curKeyCols = paragraph.chartKeyCols;
-                    const curValCols = paragraph.chartValCols;
-
-                    resetCharts = !prevKeyCols || !prevValCols ||
-                        prevKeyCols.length !== curKeyCols.length ||
-                        prevValCols.length !== curValCols.length;
-                }
-
-                _chartApplySettings(paragraph, resetCharts);
-            }
-        };
-
-        const _closeOldQuery = (paragraph) => {
-            const queryId = paragraph.queryArgs && paragraph.queryArgs.queryId;
-
-            return queryId ? agentMonitor.queryClose(queryId) : $q.when();
-        };
-
-        const _executeRefresh = (paragraph) => {
-            const args = paragraph.queryArgs;
-
-            agentMonitor.awaitAgent()
-                .then(() => _closeOldQuery(paragraph))
-                .then(() => agentMonitor.query(args.cacheName, args.pageSize, args.query))
-                .then(_processQueryResult.bind(this, paragraph))
-                .catch((err) => paragraph.errMsg = err.message);
-        };
-
-        const _tryStartRefresh = function(paragraph) {
-            _tryStopRefresh(paragraph);
-
-            if (paragraph.rate && paragraph.rate.installed && paragraph.queryArgs) {
-                $scope.chartAcceptKeyColumn(paragraph, TIME_LINE);
-
-                _executeRefresh(paragraph);
-
-                const delay = paragraph.rate.value * paragraph.rate.unit;
-
-                paragraph.rate.stopTime = $interval(_executeRefresh, delay, 0, false, paragraph);
-            }
-        };
-
-        $scope.execute = function(paragraph) {
-            QueryNotebooks.save($scope.notebook)
-                .catch(Messages.showError);
-
-            paragraph.prevQuery = paragraph.queryArgs ? paragraph.queryArgs.query : paragraph.query;
-
-            _showLoading(paragraph, true);
-
-            _closeOldQuery(paragraph)
-                .then(function() {
-                    const args = paragraph.queryArgs = {
-                        cacheName: paragraph.cacheName,
-                        pageSize: paragraph.pageSize,
-                        query: paragraph.query
-                    };
-
-                    return agentMonitor.query(args.cacheName, args.pageSize, args.query);
-                })
-                .then(function(res) {
-                    _processQueryResult(paragraph, res);
-
-                    _tryStartRefresh(paragraph);
-                })
-                .catch((err) => {
-                    paragraph.errMsg = err.message;
-
-                    _showLoading(paragraph, false);
-
-                    $scope.stopRefresh(paragraph);
-                })
-                .finally(() => paragraph.ace.focus());
-        };
-
-        $scope.queryExecuted = function(paragraph) {
-            return LegacyUtils.isDefined(paragraph.queryArgs);
-        };
-
-        const _cancelRefresh = function(paragraph) {
-            if (paragraph.rate && paragraph.rate.stopTime) {
-                delete paragraph.queryArgs;
-
-                paragraph.rate.installed = false;
-
-                $interval.cancel(paragraph.rate.stopTime);
-
-                delete paragraph.rate.stopTime;
-            }
-        };
-
-        $scope.explain = function(paragraph) {
-            QueryNotebooks.save($scope.notebook)
-                .catch(Messages.showError);
-
-            _cancelRefresh(paragraph);
-
-            _showLoading(paragraph, true);
-
-            _closeOldQuery(paragraph)
-                .then(function() {
-                    const args = paragraph.queryArgs = {
-                        cacheName: paragraph.cacheName,
-                        pageSize: paragraph.pageSize,
-                        query: 'EXPLAIN ' + paragraph.query
-                    };
-
-                    return agentMonitor.query(args.cacheName, args.pageSize, args.query);
-                })
-                .then(_processQueryResult.bind(this, paragraph))
-                .catch((err) => {
-                    paragraph.errMsg = err.message;
-
-                    _showLoading(paragraph, false);
-                })
-                .finally(() => paragraph.ace.focus());
-        };
-
-        $scope.scan = function(paragraph) {
-            QueryNotebooks.save($scope.notebook)
-                .catch(Messages.showError);
-
-            _cancelRefresh(paragraph);
-
-            _showLoading(paragraph, true);
-
-            _closeOldQuery(paragraph)
-                .then(() => {
-                    const args = paragraph.queryArgs = {
-                        cacheName: paragraph.cacheName,
-                        pageSize: paragraph.pageSize
-                    };
-
-                    return agentMonitor.query(args.cacheName, args.pageSize);
-                })
-                .then(_processQueryResult.bind(this, paragraph))
-                .catch((err) => {
-                    paragraph.errMsg = err.message;
-
-                    _showLoading(paragraph, false);
-                })
-                .finally(() => paragraph.ace.focus());
-        };
-
-        function _updatePieChartsWithData(paragraph, newDatum) {
-            $timeout(() => {
-                _.forEach(paragraph.charts, function(chart) {
-                    const chartDatum = chart.data;
-
-                    chartDatum.length = 0;
-
-                    _.forEach(newDatum, function(series) {
-                        if (chart.options.title.text === series.key)
-                            _.forEach(series.values, (v) => chartDatum.push(v));
-                    });
-                });
-
-                _.forEach(paragraph.charts, (chart) => chart.api.update());
-            });
-        }
-
-        $scope.nextPage = function(paragraph) {
-            _showLoading(paragraph, true);
-
-            paragraph.queryArgs.pageSize = paragraph.pageSize;
-
-            agentMonitor.next(paragraph.queryId, paragraph.pageSize)
-                .then(function(res) {
-                    paragraph.page++;
-
-                    paragraph.total += paragraph.rows.length;
-
-                    paragraph.rows = res.items;
-
-                    if (paragraph.chart()) {
-                        if (paragraph.result === 'pie')
-                            _updatePieChartsWithData(paragraph, _pieChartDatum(paragraph));
-                        else
-                            _updateChartsWithData(paragraph, _chartDatum(paragraph));
-                    }
-
-                    paragraph.gridOptions.updateRows(paragraph.rows);
-
-                    _showLoading(paragraph, false);
-
-                    if (res.last)
-                        delete paragraph.queryId;
-                })
-                .catch((err) => {
-                    paragraph.errMsg = err.message;
-
-                    _showLoading(paragraph, false);
-                })
-                .finally(() => paragraph.ace.focus());
-        };
-
-        const _export = (fileName, columnFilter, meta, rows) => {
-            let csvContent = '';
-
-            const cols = [];
-            const excludedCols = [];
-
-            if (meta) {
-                _.forEach(meta, (col, idx) => {
-                    if (columnFilter(col))
-                        cols.push(_fullColName(col));
-                    else
-                        excludedCols.push(idx);
-                });
-
-                csvContent += cols.join(';') + '\n';
-            }
-
-            _.forEach(rows, (row) => {
-                cols.length = 0;
-
-                if (Array.isArray(row)) {
-                    _.forEach(row, (elem, idx) => {
-                        if (_.includes(excludedCols, idx))
-                            return;
-
-                        cols.push(_.isUndefined(elem) ? '' : JSON.stringify(elem));
-                    });
-                }
-                else {
-                    _.forEach(meta, (col) => {
-                        if (columnFilter(col)) {
-                            const elem = row[col.fieldName];
-
-                            cols.push(_.isUndefined(elem) ? '' : JSON.stringify(elem));
-                        }
-                    });
-                }
-
-                csvContent += cols.join(';') + '\n';
-            });
-
-            LegacyUtils.download('application/octet-stream;charset=utf-8', fileName, escape(csvContent));
-        };
-
-        $scope.exportCsv = function(paragraph) {
-            _export(paragraph.name + '.csv', paragraph.columnFilter, paragraph.meta, paragraph.rows);
-
-            // paragraph.gridOptions.api.exporter.csvExport(uiGridExporterConstants.ALL, uiGridExporterConstants.VISIBLE);
-        };
-
-        $scope.exportPdf = function(paragraph) {
-            paragraph.gridOptions.api.exporter.pdfExport(uiGridExporterConstants.ALL, uiGridExporterConstants.VISIBLE);
-        };
-
-        $scope.exportCsvAll = function(paragraph) {
-            const args = paragraph.queryArgs;
-
-            agentMonitor.queryGetAll(args.cacheName, args.query)
-                .then((res) => _export(paragraph.name + '-all.csv', paragraph.columnFilter, res.fieldsMetadata, res.items))
-                .catch(Messages.showError)
-                .finally(() => paragraph.ace.focus());
-        };
-
-        // $scope.exportPdfAll = function(paragraph) {
-        //    $http.post('/api/v1/agent/query/getAll', {query: paragraph.query, cacheName: paragraph.cacheName})
-        //        .success(function(item) {
-        //            _export(paragraph.name + '-all.csv', item.meta, item.rows);
-        //    })
-        //    .error(Messages.showError);
-        // };
-
-        $scope.rateAsString = function(paragraph) {
-            if (paragraph.rate && paragraph.rate.installed) {
-                const idx = _.findIndex($scope.timeUnit, function(unit) {
-                    return unit.value === paragraph.rate.unit;
-                });
-
-                if (idx >= 0)
-                    return ' ' + paragraph.rate.value + $scope.timeUnit[idx].short;
-
-                paragraph.rate.installed = false;
-            }
-
-            return '';
-        };
-
-        $scope.startRefresh = function(paragraph, value, unit) {
-            paragraph.rate.value = value;
-            paragraph.rate.unit = unit;
-            paragraph.rate.installed = true;
-
-            if (paragraph.queryExecuted())
-                _tryStartRefresh(paragraph);
-        };
-
-        $scope.stopRefresh = function(paragraph) {
-            paragraph.rate.installed = false;
-
-            _tryStopRefresh(paragraph);
-        };
-
-        $scope.paragraphTimeSpanVisible = function(paragraph) {
-            return paragraph.timeLineSupported() && paragraph.chartTimeLineEnabled();
-        };
-
-        $scope.paragraphTimeLineSpan = function(paragraph) {
-            if (paragraph && paragraph.timeLineSpan)
-                return paragraph.timeLineSpan.toString();
-
-            return '1';
-        };
-
-        $scope.applyChartSettings = function(paragraph) {
-            _chartApplySettings(paragraph, true);
-        };
-
-        $scope.actionAvailable = function(paragraph, needQuery) {
-            return $scope.caches.length > 0 && (!needQuery || paragraph.query) && !paragraph.loading;
-        };
-
-        $scope.actionTooltip = function(paragraph, action, needQuery) {
-            if ($scope.actionAvailable(paragraph, needQuery))
-                return;
-
-            if (paragraph.loading)
-                return 'Waiting for server response';
-
-            return 'To ' + action + ' query select cache' + (needQuery ? ' and input query' : '');
-        };
-
-        $scope.clickableMetadata = function(node) {
-            return node.type.slice(0, 5) !== 'index';
-        };
-
-        $scope.dblclickMetadata = function(paragraph, node) {
-            paragraph.ace.insert(node.name);
-
-            setTimeout(function() {
-                paragraph.ace.focus();
-            }, 1);
-        };
-
-        $scope.importMetadata = function() {
-            Loading.start('loadingCacheMetadata');
-
-            $scope.metadata = [];
-
-            agentMonitor.metadata()
-                .then((metadata) => {
-                    $scope.metadata = _.sortBy(_.filter(metadata, (meta) => {
-                        const cache = _.find($scope.caches, { name: meta.cacheName });
-
-                        if (cache) {
-                            meta.name = (cache.sqlSchema || '"' + meta.cacheName + '"') + '.' + meta.typeName;
-                            meta.displayName = (cache.sqlSchema || meta.maskedName) + '.' + meta.typeName;
-
-                            if (cache.sqlSchema)
-                                meta.children.unshift({type: 'plain', name: 'cacheName: ' + meta.maskedName, maskedName: meta.maskedName});
-
-                            meta.children.unshift({type: 'plain', name: 'mode: ' + cache.mode, maskedName: meta.maskedName});
-                        }
-
-                        return cache;
-                    }), 'name');
-                })
-                .catch(Messages.showError)
-                .finally(() => Loading.finish('loadingCacheMetadata'));
-        };
-
-        $scope.showResultQuery = function(paragraph) {
-            if (LegacyUtils.isDefined(paragraph)) {
-                const scope = $scope.$new();
-
-                if (_.isNil(paragraph.queryArgs.query)) {
-                    scope.title = 'SCAN query';
-                    scope.content = [`SCAN query for cache: <b>${$scope.maskCacheName(paragraph.queryArgs.cacheName)}</b>`];
-                }
-                else if (paragraph.queryArgs.query .startsWith('EXPLAIN ')) {
-                    scope.title = 'Explain query';
-                    scope.content = [paragraph.queryArgs.query];
-                }
-                else {
-                    scope.title = 'SQL query';
-                    scope.content = [paragraph.queryArgs.query];
-                }
-
-                // Show a basic modal from a controller
-                $modal({scope, template: '/templates/message.html', placement: 'center', show: true});
-            }
-        };
-    }
-]];

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/src/main/js/generator/generator-common.js
----------------------------------------------------------------------
diff --git a/modules/web-console/src/main/js/generator/generator-common.js b/modules/web-console/src/main/js/generator/generator-common.js
deleted file mode 100644
index 10bd299..0000000
--- a/modules/web-console/src/main/js/generator/generator-common.js
+++ /dev/null
@@ -1,611 +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.
- */
-
-// Entry point for common functions for code generation.
-const $generatorCommon = {};
-
-// Add leading zero.
-$generatorCommon.addLeadingZero = function(numberStr, minSize) {
-    if (typeof (numberStr) !== 'string')
-        numberStr = String(numberStr);
-
-    while (numberStr.length < minSize)
-        numberStr = '0' + numberStr;
-
-    return numberStr;
-};
-
-// Format date to string.
-$generatorCommon.formatDate = function(date) {
-    const dd = $generatorCommon.addLeadingZero(date.getDate(), 2);
-    const mm = $generatorCommon.addLeadingZero(date.getMonth() + 1, 2);
-
-    const yyyy = date.getFullYear();
-
-    return mm + '/' + dd + '/' + yyyy + ' ' + $generatorCommon.addLeadingZero(date.getHours(), 2) + ':' + $generatorCommon.addLeadingZero(date.getMinutes(), 2);
-};
-
-// Generate comment for generated XML, Java, ... files.
-$generatorCommon.mainComment = function mainComment() {
-    return 'This configuration was generated by Ignite Web Console (' + $generatorCommon.formatDate(new Date()) + ')';
-};
-
-// Create result holder with service functions and properties for XML and java code generation.
-$generatorCommon.builder = function(deep) {
-    if (_.isNil($generatorCommon.JavaTypes))
-        $generatorCommon.JavaTypes = angular.element(document.getElementById('app')).injector().get('JavaTypes');
-
-    const res = [];
-
-    res.deep = deep || 0;
-    res.needEmptyLine = false;
-    res.lineStart = true;
-    res.datasources = [];
-    res.imports = {};
-    res.staticImports = {};
-    res.vars = {};
-
-    res.safeDeep = 0;
-    res.safeNeedEmptyLine = false;
-    res.safeImports = {};
-    res.safeDatasources = [];
-    res.safePoint = -1;
-
-    res.mergeProps = function(fromRes) {
-        if ($generatorCommon.isDefinedAndNotEmpty(fromRes)) {
-            res.datasources = fromRes.datasources;
-
-            angular.extend(res.imports, fromRes.imports);
-            angular.extend(res.staticImports, fromRes.staticImports);
-            angular.extend(res.vars, fromRes.vars);
-        }
-    };
-
-    res.mergeLines = function(fromRes) {
-        if ($generatorCommon.isDefinedAndNotEmpty(fromRes)) {
-            if (res.needEmptyLine)
-                res.push('');
-
-            _.forEach(fromRes, function(line) {
-                res.append(line);
-            });
-        }
-    };
-
-    res.startSafeBlock = function() {
-        res.safeDeep = this.deep;
-        this.safeNeedEmptyLine = this.needEmptyLine;
-        this.safeImports = _.cloneDeep(this.imports);
-        this.safeStaticImports = _.cloneDeep(this.staticImports);
-        this.safeDatasources = this.datasources.slice();
-        this.safePoint = this.length;
-    };
-
-    res.rollbackSafeBlock = function() {
-        if (this.safePoint >= 0) {
-            this.splice(this.safePoint, this.length - this.safePoint);
-
-            this.deep = res.safeDeep;
-            this.needEmptyLine = this.safeNeedEmptyLine;
-            this.datasources = this.safeDatasources;
-            this.imports = this.safeImports;
-            this.staticImports = this.safeStaticImports;
-            this.safePoint = -1;
-        }
-    };
-
-    res.asString = function() {
-        return this.join('\n');
-    };
-
-    res.append = function(s) {
-        this.push((this.lineStart ? _.repeat('    ', this.deep) : '') + s);
-
-        return this;
-    };
-
-    res.line = function(s) {
-        if (s) {
-            if (res.needEmptyLine)
-                res.push('');
-
-            res.append(s);
-        }
-
-        res.needEmptyLine = false;
-
-        res.lineStart = true;
-
-        return res;
-    };
-
-    res.startBlock = function(s) {
-        if (s) {
-            if (this.needEmptyLine)
-                this.push('');
-
-            this.append(s);
-        }
-
-        this.needEmptyLine = false;
-
-        this.lineStart = true;
-
-        this.deep++;
-
-        return this;
-    };
-
-    res.endBlock = function(s) {
-        this.deep--;
-
-        if (s)
-            this.append(s);
-
-        this.lineStart = true;
-
-        return this;
-    };
-
-    res.softEmptyLine = function() {
-        this.needEmptyLine = this.length > 0;
-    };
-
-    res.emptyLineIfNeeded = function() {
-        if (this.needEmptyLine) {
-            this.push('');
-            this.lineStart = true;
-
-            this.needEmptyLine = false;
-        }
-    };
-
-    /**
-     * Add class to imports.
-     *
-     * @param clsName Full class name.
-     * @returns {String} Short class name or full class name in case of names conflict.
-     */
-    res.importClass = function(clsName) {
-        if ($generatorCommon.JavaTypes.isJavaPrimitive(clsName))
-            return clsName;
-
-        const fullClassName = $generatorCommon.JavaTypes.fullClassName(clsName);
-
-        const dotIdx = fullClassName.lastIndexOf('.');
-
-        const shortName = dotIdx > 0 ? fullClassName.substr(dotIdx + 1) : fullClassName;
-
-        if (this.imports[shortName]) {
-            if (this.imports[shortName] !== fullClassName)
-                return fullClassName; // Short class names conflict. Return full name.
-        }
-        else
-            this.imports[shortName] = fullClassName;
-
-        return shortName;
-    };
-
-    /**
-     * Add class to imports.
-     *
-     * @param member Static member.
-     * @returns {String} Short class name or full class name in case of names conflict.
-     */
-    res.importStatic = function(member) {
-        const dotIdx = member.lastIndexOf('.');
-
-        const shortName = dotIdx > 0 ? member.substr(dotIdx + 1) : member;
-
-        if (this.staticImports[shortName]) {
-            if (this.staticImports[shortName] !== member)
-                return member; // Short class names conflict. Return full name.
-        }
-        else
-            this.staticImports[shortName] = member;
-
-        return shortName;
-    };
-
-    /**
-     * @returns String with "java imports" section.
-     */
-    res.generateImports = function() {
-        const genImports = [];
-
-        for (const clsName in this.imports) {
-            if (this.imports.hasOwnProperty(clsName) && this.imports[clsName].lastIndexOf('java.lang.', 0) !== 0)
-                genImports.push('import ' + this.imports[clsName] + ';');
-        }
-
-        genImports.sort();
-
-        return genImports.join('\n');
-    };
-
-    /**
-     * @returns String with "java imports" section.
-     */
-    res.generateStaticImports = function() {
-        const statImports = [];
-
-        for (const clsName in this.staticImports) {
-            if (this.staticImports.hasOwnProperty(clsName) && this.staticImports[clsName].lastIndexOf('java.lang.', 0) !== 0)
-                statImports.push('import static ' + this.staticImports[clsName] + ';');
-        }
-
-        statImports.sort();
-
-        return statImports.join('\n');
-    };
-
-    return res;
-};
-
-// Eviction policies code generation descriptors.
-$generatorCommon.EVICTION_POLICIES = {
-    LRU: {
-        className: 'org.apache.ignite.cache.eviction.lru.LruEvictionPolicy',
-        fields: {batchSize: {dflt: 1}, maxMemorySize: null, maxSize: {dflt: 100000}}
-    },
-    FIFO: {
-        className: 'org.apache.ignite.cache.eviction.fifo.FifoEvictionPolicy',
-        fields: {batchSize: {dflt: 1}, maxMemorySize: null, maxSize: {dflt: 100000}}
-    },
-    SORTED: {
-        className: 'org.apache.ignite.cache.eviction.sorted.SortedEvictionPolicy',
-        fields: {batchSize: {dflt: 1}, maxMemorySize: null, maxSize: {dflt: 100000}}
-    }
-};
-
-// Marshaller code generation descriptors.
-$generatorCommon.MARSHALLERS = {
-    OptimizedMarshaller: {
-        className: 'org.apache.ignite.marshaller.optimized.OptimizedMarshaller',
-        fields: {poolSize: null, requireSerializable: null }
-    },
-    JdkMarshaller: {
-        className: 'org.apache.ignite.marshaller.jdk.JdkMarshaller',
-        fields: {}
-    }
-};
-
-// Pairs of supported databases and their JDBC dialects.
-$generatorCommon.JDBC_DIALECTS = {
-    Generic: 'org.apache.ignite.cache.store.jdbc.dialect.BasicJdbcDialect',
-    Oracle: 'org.apache.ignite.cache.store.jdbc.dialect.OracleDialect',
-    DB2: 'org.apache.ignite.cache.store.jdbc.dialect.DB2Dialect',
-    SQLServer: 'org.apache.ignite.cache.store.jdbc.dialect.SQLServerDialect',
-    MySQL: 'org.apache.ignite.cache.store.jdbc.dialect.MySQLDialect',
-    PostgreSQL: 'org.apache.ignite.cache.store.jdbc.dialect.BasicJdbcDialect',
-    H2: 'org.apache.ignite.cache.store.jdbc.dialect.H2Dialect'
-};
-
-// Return JDBC dialect full class name for specified database.
-$generatorCommon.jdbcDialectClassName = function(db) {
-    const dialectClsName = $generatorCommon.JDBC_DIALECTS[db];
-
-    return dialectClsName ? dialectClsName : 'Unknown database: ' + db;
-};
-
-// Generate default data cache for specified igfs instance.
-$generatorCommon.igfsDataCache = function(igfs) {
-    return {
-        name: igfs.name + '-data',
-        cacheMode: 'PARTITIONED',
-        atomicityMode: 'TRANSACTIONAL',
-        writeSynchronizationMode: 'FULL_SYNC',
-        backups: 0,
-        igfsAffinnityGroupSize: igfs.affinnityGroupSize || 512
-    };
-};
-
-// Generate default meta cache for specified igfs instance.
-$generatorCommon.igfsMetaCache = function(igfs) {
-    return {
-        name: igfs.name + '-meta',
-        cacheMode: 'REPLICATED',
-        atomicityMode: 'TRANSACTIONAL',
-        writeSynchronizationMode: 'FULL_SYNC'
-    };
-};
-
-// Pairs of supported databases and their data sources.
-$generatorCommon.DATA_SOURCES = {
-    Generic: 'com.mchange.v2.c3p0.ComboPooledDataSource',
-    Oracle: 'oracle.jdbc.pool.OracleDataSource',
-    DB2: 'com.ibm.db2.jcc.DB2DataSource',
-    SQLServer: 'com.microsoft.sqlserver.jdbc.SQLServerDataSource',
-    MySQL: 'com.mysql.jdbc.jdbc2.optional.MysqlDataSource',
-    PostgreSQL: 'org.postgresql.ds.PGPoolingDataSource',
-    H2: 'org.h2.jdbcx.JdbcDataSource'
-};
-
-// Return data source full class name for specified database.
-$generatorCommon.dataSourceClassName = function(db) {
-    const dsClsName = $generatorCommon.DATA_SOURCES[db];
-
-    return dsClsName ? dsClsName : 'Unknown database: ' + db;
-};
-
-// Store factories code generation descriptors.
-$generatorCommon.STORE_FACTORIES = {
-    CacheJdbcPojoStoreFactory: {
-        className: 'org.apache.ignite.cache.store.jdbc.CacheJdbcPojoStoreFactory',
-        suffix: 'JdbcPojo',
-        fields: {
-            configuration: {type: 'bean'}
-        }
-    },
-    CacheJdbcBlobStoreFactory: {
-        className: 'org.apache.ignite.cache.store.jdbc.CacheJdbcBlobStoreFactory',
-        suffix: 'JdbcBlob',
-        fields: {
-            initSchema: null,
-            createTableQuery: null,
-            loadQuery: null,
-            insertQuery: null,
-            updateQuery: null,
-            deleteQuery: null
-        }
-    },
-    CacheHibernateBlobStoreFactory: {
-        className: 'org.apache.ignite.cache.store.hibernate.CacheHibernateBlobStoreFactory',
-        suffix: 'Hibernate',
-        fields: {hibernateProperties: {type: 'propertiesAsList', propVarName: 'props'}}
-    }
-};
-
-// Swap space SPI code generation descriptor.
-$generatorCommon.SWAP_SPACE_SPI = {
-    className: 'org.apache.ignite.spi.swapspace.file.FileSwapSpaceSpi',
-    fields: {
-        baseDirectory: {type: 'path'},
-        readStripesNumber: null,
-        maximumSparsity: {type: 'float'},
-        maxWriteQueueSize: null,
-        writeBufferSize: null
-    }
-};
-
-// Transaction configuration code generation descriptor.
-$generatorCommon.TRANSACTION_CONFIGURATION = {
-    className: 'org.apache.ignite.configuration.TransactionConfiguration',
-    fields: {
-        defaultTxConcurrency: {type: 'enum', enumClass: 'org.apache.ignite.transactions.TransactionConcurrency', dflt: 'PESSIMISTIC'},
-        defaultTxIsolation: {type: 'enum', enumClass: 'org.apache.ignite.transactions.TransactionIsolation', dflt: 'REPEATABLE_READ'},
-        defaultTxTimeout: {dflt: 0},
-        pessimisticTxLogLinger: {dflt: 10000},
-        pessimisticTxLogSize: null,
-        txSerializableEnabled: null,
-        txManagerFactory: {type: 'bean'}
-    }
-};
-
-// SSL configuration code generation descriptor.
-$generatorCommon.SSL_CONFIGURATION_TRUST_FILE_FACTORY = {
-    className: 'org.apache.ignite.ssl.SslContextFactory',
-    fields: {
-        keyAlgorithm: null,
-        keyStoreFilePath: {type: 'path'},
-        keyStorePassword: {type: 'raw'},
-        keyStoreType: null,
-        protocol: null,
-        trustStoreFilePath: {type: 'path'},
-        trustStorePassword: {type: 'raw'},
-        trustStoreType: null
-    }
-};
-
-// SSL configuration code generation descriptor.
-$generatorCommon.SSL_CONFIGURATION_TRUST_MANAGER_FACTORY = {
-    className: 'org.apache.ignite.ssl.SslContextFactory',
-    fields: {
-        keyAlgorithm: null,
-        keyStoreFilePath: {type: 'path'},
-        keyStorePassword: {type: 'raw'},
-        keyStoreType: null,
-        protocol: null,
-        trustManagers: {type: 'array'}
-    }
-};
-
-// Communication configuration code generation descriptor.
-$generatorCommon.CONNECTOR_CONFIGURATION = {
-    className: 'org.apache.ignite.configuration.ConnectorConfiguration',
-    fields: {
-        jettyPath: null,
-        host: null,
-        port: {dflt: 11211},
-        portRange: {dflt: 100},
-        idleTimeout: {dflt: 7000},
-        idleQueryCursorTimeout: {dflt: 600000},
-        idleQueryCursorCheckFrequency: {dflt: 60000},
-        receiveBufferSize: {dflt: 32768},
-        sendBufferSize: {dflt: 32768},
-        sendQueueLimit: {dflt: 0},
-        directBuffer: {dflt: false},
-        noDelay: {dflt: true},
-        selectorCount: null,
-        threadPoolSize: null,
-        messageInterceptor: {type: 'bean'},
-        secretKey: null,
-        sslEnabled: {dflt: false}
-    }
-};
-
-// Communication configuration code generation descriptor.
-$generatorCommon.COMMUNICATION_CONFIGURATION = {
-    className: 'org.apache.ignite.spi.communication.tcp.TcpCommunicationSpi',
-    fields: {
-        listener: {type: 'bean'},
-        localAddress: null,
-        localPort: {dflt: 47100},
-        localPortRange: {dflt: 100},
-        sharedMemoryPort: {dflt: 48100},
-        directBuffer: {dflt: false},
-        directSendBuffer: {dflt: false},
-        idleConnectionTimeout: {dflt: 30000},
-        connectTimeout: {dflt: 5000},
-        maxConnectTimeout: {dflt: 600000},
-        reconnectCount: {dflt: 10},
-        socketSendBuffer: {dflt: 32768},
-        socketReceiveBuffer: {dflt: 32768},
-        messageQueueLimit: {dflt: 1024},
-        slowClientQueueLimit: null,
-        tcpNoDelay: {dflt: true},
-        ackSendThreshold: {dflt: 16},
-        unacknowledgedMessagesBufferSize: {dflt: 0},
-        socketWriteTimeout: {dflt: 2000},
-        selectorsCount: null,
-        addressResolver: {type: 'bean'}
-    }
-};
-
-// Communication configuration code generation descriptor.
-$generatorCommon.IGFS_IPC_CONFIGURATION = {
-    className: 'org.apache.ignite.igfs.IgfsIpcEndpointConfiguration',
-    fields: {
-        type: {type: 'enum', enumClass: 'org.apache.ignite.igfs.IgfsIpcEndpointType'},
-        host: {dflt: '127.0.0.1'},
-        port: {dflt: 10500},
-        memorySize: {dflt: 262144},
-        tokenDirectoryPath: {dflt: 'ipc/shmem'}
-    }
-};
-
-// Check that cache has datasource.
-$generatorCommon.cacheHasDatasource = function(cache) {
-    if (cache.cacheStoreFactory && cache.cacheStoreFactory.kind) {
-        const storeFactory = cache.cacheStoreFactory[cache.cacheStoreFactory.kind];
-
-        return !!(storeFactory && (storeFactory.connectVia ? (storeFactory.connectVia === 'DataSource' ? storeFactory.dialect : false) : storeFactory.dialect)); // eslint-disable-line no-nested-ternary
-    }
-
-    return false;
-};
-
-$generatorCommon.secretPropertiesNeeded = function(cluster) {
-    return !_.isNil(_.find(cluster.caches, $generatorCommon.cacheHasDatasource)) || cluster.sslEnabled;
-};
-
-// Check that binary is configured.
-$generatorCommon.binaryIsDefined = function(binary) {
-    return binary && ($generatorCommon.isDefinedAndNotEmpty(binary.idMapper) || $generatorCommon.isDefinedAndNotEmpty(binary.nameMapper) ||
-        $generatorCommon.isDefinedAndNotEmpty(binary.serializer) || $generatorCommon.isDefinedAndNotEmpty(binary.typeConfigurations) ||
-        (!_.isNil(binary.compactFooter) && !binary.compactFooter));
-};
-
-// Extract domain model metadata location.
-$generatorCommon.domainQueryMetadata = function(domain) {
-    return domain.queryMetadata ? domain.queryMetadata : 'Configuration';
-};
-
-/**
- * @param {Object} obj Object to check.
- * @param {Array<String>} props Array of properties names.
- * @returns {boolean} 'true' if
- */
-$generatorCommon.hasAtLeastOneProperty = function(obj, props) {
-    return obj && props && _.findIndex(props, (prop) => !_.isNil(obj[prop])) >= 0;
-};
-
-/**
- * Convert some name to valid java name.
- *
- * @param prefix To append to java name.
- * @param name to convert.
- * @returns {string} Valid java name.
- */
-$generatorCommon.toJavaName = function(prefix, name) {
-    const javaName = name ? name.replace(/[^A-Za-z_0-9]+/g, '_') : 'dflt';
-
-    return prefix + javaName.charAt(0).toLocaleUpperCase() + javaName.slice(1);
-};
-
-/**
- * @param v Value to check.
- * @returns {boolean} 'true' if value defined and not empty string.
- */
-$generatorCommon.isDefinedAndNotEmpty = function(v) {
-    let defined = !_.isNil(v);
-
-    if (defined && (_.isString(v) || _.isArray(v)))
-        defined = v.length > 0;
-
-    return defined;
-};
-
-/**
- * @param {Object} obj Object to check.
- * @param {Array<String>} props Properties names.
- * @returns {boolean} 'true' if object contains at least one from specified properties.
- */
-$generatorCommon.hasProperty = function(obj, props) {
-    for (const propName in props) {
-        if (props.hasOwnProperty(propName)) {
-            if (obj[propName])
-                return true;
-        }
-    }
-
-    return false;
-};
-
-/**
- * Get class for selected implementation of Failover SPI.
- *
- * @param spi Failover SPI configuration.
- * @returns {*} Class for selected implementation of Failover SPI.
- */
-$generatorCommon.failoverSpiClass = function(spi) {
-    switch (spi.kind) {
-        case 'JobStealing': return 'org.apache.ignite.spi.failover.jobstealing.JobStealingFailoverSpi';
-        case 'Never': return 'org.apache.ignite.spi.failover.never.NeverFailoverSpi';
-        case 'Always': return 'org.apache.ignite.spi.failover.always.AlwaysFailoverSpi';
-        case 'Custom': return _.get(spi, 'Custom.class');
-        default: return 'Unknown';
-    }
-};
-
-$generatorCommon.loggerConfigured = function(logger) {
-    if (logger && logger.kind) {
-        const log = logger[logger.kind];
-
-        switch (logger.kind) {
-            case 'Log4j2': return log && $generatorCommon.isDefinedAndNotEmpty(log.path);
-
-            case 'Log4j':
-                if (!log || !log.mode)
-                    return false;
-
-                if (log.mode === 'Path')
-                    return $generatorCommon.isDefinedAndNotEmpty(log.path);
-
-                return true;
-
-            case 'Custom': return log && $generatorCommon.isDefinedAndNotEmpty(log.class);
-
-            default:
-                return true;
-        }
-    }
-
-    return false;
-};
-
-export default $generatorCommon;


[39/52] ignite git commit: Web Console beta-3.

Posted by ak...@apache.org.
http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/frontend/app/helpers/jade/form/form-group.jade
----------------------------------------------------------------------
diff --git a/modules/web-console/frontend/app/helpers/jade/form/form-group.jade b/modules/web-console/frontend/app/helpers/jade/form/form-group.jade
new file mode 100644
index 0000000..8fb7b1f
--- /dev/null
+++ b/modules/web-console/frontend/app/helpers/jade/form/form-group.jade
@@ -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.
+
+mixin ignite-form-group()
+    .group-section(ignite-form-group)&attributes(attributes)
+        .group(ng-if='true' ng-init='group = {}')
+            .group-legend
+                label {{::group.label}}
+            if block
+                block

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/frontend/app/helpers/jade/mixins.jade
----------------------------------------------------------------------
diff --git a/modules/web-console/frontend/app/helpers/jade/mixins.jade b/modules/web-console/frontend/app/helpers/jade/mixins.jade
new file mode 100644
index 0000000..c37ab15
--- /dev/null
+++ b/modules/web-console/frontend/app/helpers/jade/mixins.jade
@@ -0,0 +1,541 @@
+//-
+    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 ./form.jade
+
+//- Mixin for advanced options toggle.
+mixin advanced-options-toggle(click, cond, showMessage, hideMessage)
+    .advanced-options
+        i.fa(ng-click='#{click}' ng-class='#{cond} ? "fa-chevron-circle-down" : "fa-chevron-circle-right"')
+        a(ng-click=click) {{#{cond} ? '#{hideMessage}' : '#{showMessage}'}}
+
+//- Mixin for advanced options toggle with default settings.
+mixin advanced-options-toggle-default
+    +advanced-options-toggle('toggleExpanded()', 'ui.expanded', 'Show advanced settings...', 'Hide advanced settings...')
+
+//- Mixin for main table on screen with list of items.
+mixin main-table(title, rows, focusId, click, rowTemplate, searchField)
+    .padding-bottom-dflt(ng-show='#{rows} && #{rows}.length > 0')
+        table.links(st-table='displayedRows' st-safe-src='#{rows}')
+            thead
+                tr
+                    th
+                        lable.labelHeader.labelFormField #{title}:
+                        .col-sm-3.pull-right(style='padding: 0')
+                            input.form-control(type='text' st-search='#{searchField}' placeholder='Filter #{title}...')
+            tbody
+                tr
+                    td
+                        .scrollable-y(ng-show='displayedRows.length > 0' style='max-height: 200px')
+                            table
+                                tbody
+                                    tr(ng-repeat='row in displayedRows track by row._id' ignite-bs-affix-update)
+                                        td
+                                            a(ng-class='{active: row._id == selectedItem._id}' ignite-on-click-focus=focusId ng-click=click) #{rowTemplate}
+                        label.placeholder(ng-show='displayedRows.length == 0') No #{title} found
+
+//- Mixin with save, remove, clone and undo buttons.
+mixin save-remove-clone-undo-buttons(objectName)
+    -var removeTip = '"Remove current ' + objectName + '"'
+    -var cloneTip = '"Clone current ' + objectName + '"'
+    -var undoTip = '"Undo all changes for current ' + objectName + '"'
+
+    div(ng-show='contentVisible()' style='display: inline-block;')
+        .panel-tip-container(ng-hide='!backupItem || backupItem._id')
+            a.btn.btn-primary(ng-disabled='!ui.inputForm.$dirty' ng-click='ui.inputForm.$dirty && saveItem()' bs-tooltip='' data-title='{{saveBtnTipText(ui.inputForm.$dirty, "#{objectName}")}}' data-placement='bottom' data-trigger='hover') Save
+        .panel-tip-container(ng-show='backupItem._id')
+            a.btn.btn-primary(id='save-item' ng-disabled='!ui.inputForm.$dirty' ng-click='ui.inputForm.$dirty && saveItem()' bs-tooltip='' data-title='{{saveBtnTipText(ui.inputForm.$dirty, "#{objectName}")}}' data-placement='bottom' data-trigger='hover') Save
+        .panel-tip-container(ng-show='backupItem._id')
+            a.btn.btn-primary(id='clone-item' ng-click='cloneItem()' bs-tooltip=cloneTip data-placement='bottom' data-trigger='hover') Clone
+        .btn-group.panel-tip-container(ng-show='backupItem._id')
+            button.btn.btn-primary(id='remove-item' ng-click='removeItem()' bs-tooltip=removeTip data-placement='bottom' data-trigger='hover') Remove
+            button.btn.dropdown-toggle.btn-primary(id='remove-item-dropdown' data-toggle='dropdown' data-container='body' bs-dropdown='[{ text: "Remove All", click: "removeAllItems()" }]' data-placement='bottom-right')
+                span.caret
+        .panel-tip-container(ng-show='backupItem')
+            i.btn.btn-primary.fa.fa-undo(id='undo-item' ng-disabled='!ui.inputForm.$dirty' ng-click='ui.inputForm.$dirty && resetAll()' bs-tooltip=undoTip data-placement='bottom' data-trigger='hover')
+
+//- Mixin for feedback on specified error.
+mixin error-feedback(visible, error, errorMessage, name)
+    i.fa.fa-exclamation-triangle.form-control-feedback(
+        ng-if=visible
+        bs-tooltip='"#{errorMessage}"'
+        ignite-error=error
+        ignite-error-message=errorMessage
+        name=name
+    )
+
+//- Mixin for feedback on unique violation.
+mixin unique-feedback(name, errorMessage)
+    +form-field-feedback(name, 'igniteUnique', errorMessage)
+
+//- Mixin for feedback on IP address violation.
+mixin ipaddress-feedback(name)
+    +form-field-feedback(name, 'ipaddress', 'Invalid address!')
+
+//- Mixin for feedback on port of IP address violation.
+mixin ipaddress-port-feedback(name)
+    +form-field-feedback(name, 'ipaddressPort', 'Invalid port!')
+
+//- Mixin for feedback on port range violation.
+mixin ipaddress-port-range-feedback(name)
+    +form-field-feedback(name, 'ipaddressPortRange', 'Invalid port range!')
+
+//- Mixin for feedback on UUID violation.
+mixin uuid-feedback(name)
+    +form-field-feedback(name, 'uuid', 'Invalid node ID!')
+
+//- Mixin for checkbox.
+mixin checkbox(lbl, model, name, tip)
+    +form-field-checkbox(lbl, model, name, false, false, tip)
+
+//- Mixin for checkbox with enabled condition.
+mixin checkbox-enabled(lbl, model, name, enabled, tip)
+    if enabled === false || enabled === true 
+        -var disabled = !enabled
+    else
+        -var disabled = '!('+enabled+')'
+        
+    +form-field-checkbox(lbl, model, name, disabled, false, tip)
+
+//- Mixin for java name field with enabled condition.
+mixin java-class(lbl, model, name, enabled, required, tip)
+    -var errLbl = lbl.substring(0, lbl.length - 1)
+
+    if enabled === false || enabled === true 
+        -var disabled = !enabled
+    else
+        -var disabled = '!('+enabled+')'
+
+    +ignite-form-field-text(lbl, model, name, disabled, required, 'Enter fully qualified class name', tip)(
+        data-java-identifier='true'
+        data-java-package-specified='true'
+        data-java-keywords='true'
+        data-java-built-in-class='true'
+    )
+        if  block
+            block
+
+        +form-field-feedback(name, 'javaBuiltInClass', errLbl + ' should not be the Java built-in class!')
+        +form-field-feedback(name, 'javaKeywords', errLbl + ' could not contains reserved Java keyword!')
+        +form-field-feedback(name, 'javaPackageSpecified', errLbl + ' does not have package specified!')
+        +form-field-feedback(name, 'javaIdentifier', errLbl + ' is invalid Java identifier!')
+
+        
+
+//- Mixin for text field with enabled condition with options.
+mixin java-class-typeahead(lbl, model, name, options, enabled, required, placeholder, tip)
+    -var errLbl = lbl.substring(0, lbl.length - 1)
+
+    +form-field-datalist(lbl, model, name, '!('+enabled+')', required, placeholder, options, tip)(
+        data-java-identifier='true'
+        data-java-package-specified='allow-built-in'
+        data-java-keywords='true'
+    )
+        +form-field-feedback(name, 'javaKeywords', errLbl + ' could not contains reserved Java keyword!')
+        +form-field-feedback(name, 'javaPackageSpecified', errLbl + ' does not have package specified!')
+        +form-field-feedback(name, 'javaIdentifier', errLbl + ' is invalid Java identifier!')
+
+//- Mixin for text field with IP address check.
+mixin text-ip-address(lbl, model, name, enabled, placeholder, tip)
+    +ignite-form-field-text(lbl, model, name, '!('+enabled+')', false, placeholder, tip)(data-ipaddress='true')
+        +ipaddress-feedback(name)
+
+//- Mixin for text field with IP address and port check.
+mixin text-ip-address-with-port(lbl, model, name, enabled, placeholder, tip)
+    +ignite-form-field-text(lbl, model, name, '!('+enabled+')', false, placeholder, tip)(data-ipaddress='true' data-ipaddress-with-port='true')
+        +ipaddress-feedback(name)
+        +ipaddress-port-feedback(name)
+
+//- Mixin for text field.
+mixin text-enabled(lbl, model, name, enabled, required, placeholder, tip)
+    if enabled === false || enabled === true 
+        -var disabled = !enabled
+    else
+        -var disabled = '!('+enabled+')'
+        
+    +ignite-form-field-text(lbl, model, name, disabled, required, placeholder, tip)
+        if  block
+            block
+
+//- Mixin for text field.
+mixin text(lbl, model, name, required, placeholder, tip)
+    +ignite-form-field-text(lbl, model, name, false, required, placeholder, tip)
+        if  block
+            block
+
+//- Mixin for text field with enabled condition with options.
+mixin text-options(lbl, model, name, options, enabled, required, placeholder, tip)
+    +form-field-datalist(lbl, model, name, '!('+enabled+')', required, placeholder, options, tip)
+
+//- Mixin for required numeric field.
+mixin number-required(lbl, model, name, enabled, required, placeholder, min, tip)
+    +ignite-form-field-number(lbl, model, name, '!('+enabled+')', required, placeholder, min, false, false, tip)
+
+//- Mixin for required numeric field with maximum and minimum limit.
+mixin number-min-max(lbl, model, name, enabled, placeholder, min, max, tip)
+    +ignite-form-field-number(lbl, model, name, '!('+enabled+')', false, placeholder, min, max, '1', tip)
+
+//- Mixin for required numeric field with maximum and minimum limit.
+mixin number-min-max-step(lbl, model, name, enabled, placeholder, min, max, step, tip)
+    +ignite-form-field-number(lbl, model, name, '!('+enabled+')', false, placeholder, min, max, step, tip)
+
+//- Mixin for numeric field.
+mixin number(lbl, model, name, enabled, placeholder, min, tip)
+    +ignite-form-field-number(lbl, model, name, '!('+enabled+')', false, placeholder, min, false, false, tip)
+
+//- Mixin for required dropdown field.
+mixin dropdown-required-empty(lbl, model, name, enabled, required, placeholder, placeholderEmpty, options, tip)
+    if enabled === false || enabled === true 
+        -var disabled = !enabled
+    else
+        -var disabled = '!('+enabled+')'
+
+    +ignite-form-field-dropdown(lbl, model, name, disabled, required, false, placeholder, placeholderEmpty, options, tip)
+        if  block
+            block
+                
+//- Mixin for required dropdown field.
+mixin dropdown-required(lbl, model, name, enabled, required, placeholder, options, tip)
+    if enabled === false || enabled === true 
+        -var disabled = !enabled
+    else
+        -var disabled = '!('+enabled+')'
+
+    +ignite-form-field-dropdown(lbl, model, name, disabled, required, false, placeholder, '', options, tip)
+        if  block
+            block
+
+//- Mixin for dropdown field.
+mixin dropdown(lbl, model, name, enabled, placeholder, options, tip)
+    if enabled === false || enabled === true 
+        -var disabled = !enabled
+    else
+        -var disabled = '!('+enabled+')'
+
+    +ignite-form-field-dropdown(lbl, model, name, disabled, false, false, placeholder, '', options, tip)
+        if  block
+            block
+
+//- Mixin for dropdown-multiple field.
+mixin dropdown-multiple(lbl, model, name, enabled, placeholder, placeholderEmpty, options, tip)
+    if enabled === false || enabled === true 
+        -var disabled = !enabled
+    else
+        -var disabled = '!('+enabled+')'
+
+    +ignite-form-field-dropdown(lbl, model, name, disabled, false, true, placeholder, placeholderEmpty, options, tip)
+        if  block
+            block
+
+//- Mixin for table text field.
+mixin table-text-field(name, model, items, valid, save, placeholder, newItem)
+    -var resetOnEnter = newItem ? '(stopblur = true) && (group.add = [{}])' : '(field.edit = false)'
+    -var onEnter = valid + ' && (' + save + '); ' + valid + ' && ' + resetOnEnter + ';'
+
+    -var onEscape = newItem ? 'group.add = []' : 'field.edit = false'
+
+    -var resetOnBlur = newItem ? '!stopblur && (group.add = [])' : 'field.edit = false'
+    -var onBlur = valid + ' && ( ' + save + '); ' + resetOnBlur + ';'
+
+    if block
+        block
+
+    .input-tip
+        +ignite-form-field-input(name, model, false, 'true', placeholder)(
+            data-ignite-unique=items
+            data-ignite-form-field-input-autofocus='true'
+            ng-blur=onBlur
+            ignite-on-enter=onEnter
+            ignite-on-escape=onEscape
+        )
+
+//- Mixin for table java class field.
+mixin table-java-class-field(lbl, name, model, items, valid, save, newItem)
+    -var errLbl = lbl.substring(0, lbl.length - 1)
+
+    -var resetOnEnter = newItem ? '(stopblur = true) && (group.add = [{}])' : '(field.edit = false)'
+    -var onEnter = valid + ' && (' + save + '); ' + valid + ' && ' + resetOnEnter + ';'
+
+    -var onEscape = newItem ? 'group.add = []' : 'field.edit = false'
+
+    -var resetOnBlur = newItem ? '!stopblur && (group.add = [])' : 'field.edit = false'
+    -var onBlur = valid + ' && ( ' + save + '); ' + resetOnBlur + ';'
+
+    if block
+        block
+
+    +form-field-feedback(name, 'javaBuiltInClass', errLbl + ' should not be the Java built-in class!')
+    +form-field-feedback(name, 'javaKeywords', errLbl + ' could not contains reserved Java keyword!')
+    +form-field-feedback(name, 'javaPackageSpecified', errLbl + ' does not have package specified!')
+    +form-field-feedback(name, 'javaIdentifier', errLbl + ' is invalid Java identifier!')
+
+    if block
+        block
+
+    .input-tip
+        +ignite-form-field-input(name, model, false, 'true', 'Enter fully qualified class name')(
+            data-java-identifier='true'
+            data-java-package-specified='true'
+            data-java-keywords='true'
+            data-java-built-in-class='true'
+
+            data-ignite-unique=items
+            data-ignite-form-field-input-autofocus='true'
+
+            ng-blur=onBlur
+            ignite-on-enter=onEnter
+            ignite-on-escape=onEscape
+        )
+
+//- Mixin for table java package field.
+mixin table-java-package-field(name, model, items, valid, save, newItem)
+    -var resetOnEnter = newItem ? '(stopblur = true) && (group.add = [{}])' : '(field.edit = false)'
+    -var onEnter = valid + ' && (' + save + '); ' + valid + ' && ' + resetOnEnter + ';'
+
+    -var onEscape = newItem ? 'group.add = []' : 'field.edit = false'
+
+    -var resetOnBlur = newItem ? '!stopblur && (group.add = [])' : 'field.edit = false'
+    -var onBlur = valid + ' && ( ' + save + '); ' + resetOnBlur + ';'
+
+    +form-field-feedback(name, 'javaKeywords', 'Package name could not contains reserved Java keyword!')
+    +form-field-feedback(name, 'javaPackageName', 'Package name is invalid!')
+
+    if block
+        block
+
+    .input-tip
+        +ignite-form-field-input(name, model, false, 'true', 'Enter package name')(
+            data-java-keywords='true'
+            data-java-package-name='true'
+
+            data-ignite-unique=items
+            data-ignite-form-field-input-autofocus='true'
+
+            ng-blur=onBlur
+            ignite-on-enter=onEnter
+            ignite-on-escape=onEscape
+        )
+
+
+//- Mixin for table address field.
+mixin table-address-field(name, model, items, valid, save, newItem, portRange)
+    -var resetOnEnter = newItem ? '(stopblur = true) && (group.add = [{}])' : '(field.edit = false)'
+    -var onEnter = valid + ' && (' + save + '); ' + valid + ' && ' + resetOnEnter + ';'
+
+    -var onEscape = newItem ? 'group.add = []' : 'field.edit = false'
+
+    -var resetOnBlur = newItem ? '!stopblur && (group.add = [])' : 'field.edit = false'
+    -var onBlur = valid + ' && ( ' + save + '); ' + resetOnBlur + ';'
+
+    +ipaddress-feedback(name)
+    +ipaddress-port-feedback(name)
+    +ipaddress-port-range-feedback(name)
+
+    if block
+        block
+
+    .input-tip
+        +ignite-form-field-input(name, model, false, 'true', 'IP address:port')(
+            data-ipaddress='true'
+            data-ipaddress-with-port='true'
+            data-ipaddress-with-port-range=portRange ? 'true' : null
+            data-ignite-unique=items
+            data-ignite-form-field-input-autofocus='true'
+            ng-blur=onBlur
+            ignite-on-enter=onEnter
+            ignite-on-escape=onEscape
+        )
+
+//- Mixin for table UUID field.
+mixin table-uuid-field(name, model, items, valid, save, newItem, portRange)
+    -var resetOnEnter = newItem ? '(stopblur = true) && (group.add = [{}])' : '(field.edit = false)'
+    -var onEnter = valid + ' && (' + save + '); ' + valid + ' && ' + resetOnEnter + ';'
+
+    -var onEscape = newItem ? 'group.add = []' : 'field.edit = false'
+
+    -var resetOnBlur = newItem ? '!stopblur && (group.add = [])' : 'field.edit = false'
+    -var onBlur = valid + ' && ( ' + save + '); ' + resetOnBlur + ';'
+
+    if block
+        block
+
+    .input-tip
+        +ignite-form-field-input(name, model, false, 'true', 'xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx')(
+            data-uuid='true'
+            data-ignite-unique=items
+            data-ignite-form-field-input-autofocus='true'
+            ng-blur=onBlur
+            ignite-on-enter=onEnter
+            ignite-on-escape=onEscape
+        )
+
+//- Mixin for table save button.
+   "||" used instead of "&&" to workaround escaping of "&&" to "&amp;&amp;"
+mixin table-save-button(valid, save, newItem)
+    -var reset = newItem ? 'group.add = []' : 'field.edit = false'
+
+    i.fa.fa-floppy-o.form-field-save(
+        ng-show=valid
+        ng-click='!(#{valid}) || (#{save}); !(#{valid}) || (#{reset});'
+        bs-tooltip
+        data-title='Click icon or press [Enter] to save item'
+    )
+
+//- Mixin for table remove button.
+mixin table-remove-conditional-button(items, show, tip)
+    i.tipField.fa.fa-remove(
+        ng-hide='!#{show} || field.edit'
+        bs-tooltip
+        data-title=tip
+        ng-click='#{items}.splice(#{items}.indexOf(model), 1)'
+    )
+
+//- Mixin for table remove button.
+mixin table-remove-button(items, tip)
+    +table-remove-conditional-button(items, 'true', tip)
+
+//- Mixin for cache mode.
+mixin cacheMode(lbl, model, name, placeholder)
+    +dropdown(lbl, model, name, 'true', placeholder,
+        '[\
+            {value: "LOCAL", label: "LOCAL"},\
+            {value: "REPLICATED", label: "REPLICATED"},\
+            {value: "PARTITIONED", label: "PARTITIONED"}\
+        ]',
+        'Cache modes:\
+        <ul>\
+            <li>PARTITIONED - in this mode the overall key set will be divided into partitions and all partitions will be split equally between participating nodes</li>\
+            <li>REPLICATED - in this mode all the keys are distributed to all participating nodes</li>\
+            <li>LOCAL - in this mode caches residing on different grid nodes will not know about each other</li>\
+        </ul>'
+    )
+
+//- Mixin for eviction policy.
+mixin evictionPolicy(model, name, enabled, required, tip)
+    -var kind = model + '.kind'
+    -var policy = model + '[' + kind + ']'
+
+    +dropdown-required('Eviction policy:', kind, name + '+ "Kind"', enabled, required, 'Not set',
+        '[\
+            {value: "LRU", label: "LRU"},\
+            {value: "FIFO", label: "FIFO"},\
+            {value: "SORTED", label: "Sorted"},\
+            {value: undefined, label: "Not set"}\
+        ]', tip)
+    span(ng-if=kind ng-init='__ = {};')
+        a.customize(ng-show='__.expanded' ng-click='__.expanded = false') Hide settings
+        a.customize(ng-hide='__.expanded' ng-click='__.expanded = true') Show settings
+        .panel-details(ng-if='__.expanded')
+            .details-row
+                +number('Batch size', policy + '.batchSize', name + '+ "batchSize"', enabled, '1', '0',
+                    'Number of entries to remove on shrink')
+            .details-row
+                +number('Max memory size', policy + '.maxMemorySize', name + '+ "maxMemorySize"', enabled, '0', '0',
+                    'Maximum allowed cache size in bytes')
+            .details-row
+                +number('Max size', policy + '.maxSize', name + '+ "maxSize"', enabled, '100000', '0',
+                    'Maximum allowed size of cache before entry will start getting evicted')
+
+//- Mixin for clusters dropdown.
+mixin clusters(model, tip)
+    +dropdown-multiple('<span>Clusters:</span>' + '<a ui-sref="base.configuration.clusters({linkId: linkId()})"> (add)</a>',
+        model + '.clusters', '"clusters"', true, 'Choose clusters', 'No clusters configured', 'clusters', tip)
+
+//- Mixin for caches dropdown.
+mixin caches(model, tip)
+    +dropdown-multiple('<span>Caches:</span>' + '<a ui-sref="base.configuration.caches({linkId: linkId()})"> (add)</a>',
+        model + '.caches', '"caches"', true, 'Choose caches', 'No caches configured', 'caches', tip)
+
+//- Mixin for XML and Java preview.
+mixin preview-xml-java(master, generator, detail)
+    ignite-ui-ace-tabs
+        .preview-panel
+            .preview-legend
+                a(ng-class='{active: !mode, inactive: mode}' ng-click='mode = false') XML
+                | &nbsp;
+                a(ng-class='{active: mode, inactive: !mode}' ng-click='mode = true') Java
+            .preview-content(ng-if='mode')
+                ignite-ui-ace-java(data-master=master data-generator=generator ng-model='$parent.data' data-detail=detail)
+            .preview-content(ng-if='!mode')
+                ignite-ui-ace-xml(data-master=master data-generator=generator ng-model='$parent.data' data-detail=detail)
+            .preview-content-empty(ng-if='!data')
+                label All Defaults
+
+//- LEGACY mixin for LEGACY tables.
+mixin btn-save(show, click)
+    i.tipField.fa.fa-floppy-o(ng-show=show ng-click=click bs-tooltip='' data-title='Click icon or press [Enter] to save item' data-trigger='hover')
+
+//- LEGACY mixin for LEGACY tables.
+mixin btn-add(click, tip)
+    i.tipField.fa.fa-plus(ng-click=click bs-tooltip=tip data-trigger = 'hover')
+
+//- LEGACY mixin for LEGACY tables.
+mixin btn-remove(click, tip)
+    i.tipField.fa.fa-remove(ng-click=click bs-tooltip=tip data-trigger='hover')
+
+//- LEGACY mixin for LEGACY tables.
+mixin btn-remove-cond(cond, click, tip)
+    i.tipField.fa.fa-remove(ng-show=cond ng-click=click bs-tooltip=tip data-trigger='hover')
+
+//- LEGACY mixin for LEGACY pair values tables.
+mixin table-pair-edit(tbl, prefix, keyPlaceholder, valPlaceholder, keyJavaBuiltInTypes, valueJavaBuiltInTypes, focusId, index, divider)
+    -var keyModel = tbl + '.' + prefix + 'Key'
+    -var valModel = tbl +'.' + prefix + 'Value'
+
+    -var keyFocusId = prefix + 'Key' + focusId
+    -var valFocusId = prefix + 'Value' + focusId
+
+    .col-xs-6.col-sm-6.col-md-6
+        .fieldSep !{divider}
+        .input-tip
+            if keyJavaBuiltInTypes
+                input.form-control(id=keyFocusId ignite-on-enter-focus-move=valFocusId type='text' ng-model=keyModel placeholder=keyPlaceholder bs-typeahead container='body' ignite-retain-selection data-min-length='1' bs-options='javaClass for javaClass in javaBuiltInClasses' ignite-on-escape='tableReset()')
+            else
+                input.form-control(id=keyFocusId ignite-on-enter-focus-move=valFocusId type='text' ng-model=keyModel placeholder=keyPlaceholder ignite-on-escape='tableReset()')
+    .col-xs-6.col-sm-6.col-md-6
+        -var arg = keyModel + ', ' + valModel
+        -var btnVisible = 'tablePairSaveVisible(' + tbl + ', ' + index + ')'
+        -var btnSave = 'tablePairSave(tablePairValid, backupItem, ' + tbl + ', ' + index + ')'
+        -var btnVisibleAndSave = btnVisible + ' && ' + btnSave
+
+        +btn-save(btnVisible, btnSave)
+        .input-tip
+            if valueJavaBuiltInTypes
+                input.form-control(id=valFocusId type='text' ng-model=valModel placeholder=valPlaceholder bs-typeahead container='body' ignite-retain-selection data-min-length='1' bs-options='javaClass for javaClass in javaBuiltInClasses' ignite-on-enter=btnVisibleAndSave ignite-on-escape='tableReset()')
+            else
+                input.form-control(id=valFocusId type='text' ng-model=valModel placeholder=valPlaceholder ignite-on-enter=btnVisibleAndSave ignite-on-escape='tableReset()')
+
+//- Mixin for DB dialect.
+mixin dialect(lbl, model, name, required, tipTitle, genericDialectName, placeholder)
+    +dropdown(lbl, model, name, required, placeholder, '[\
+                {value: "Generic", label: "' + genericDialectName + '"},\
+                {value: "Oracle", label: "Oracle"},\
+                {value: "DB2", label: "IBM DB2"},\
+                {value: "SQLServer", label: "Microsoft SQL Server"},\
+                {value: "MySQL", label: "MySQL"},\
+                {value: "PostgreSQL", label: "PostgreSQL"},\
+                {value: "H2", label: "H2 database"}\
+        ]',
+        tipTitle + 
+        '<ul>\
+            <li>' + genericDialectName + '</li>\
+            <li>Oracle database</li>\
+            <li>IBM DB2</li>\
+            <li>Microsoft SQL Server</li>\
+            <li>MySQL</li>\
+            <li>PostgreSQL</li>\
+            <li>H2 database</li>\
+        </ul>')

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/frontend/app/modules/Demo/Demo.module.js
----------------------------------------------------------------------
diff --git a/modules/web-console/frontend/app/modules/Demo/Demo.module.js b/modules/web-console/frontend/app/modules/Demo/Demo.module.js
new file mode 100644
index 0000000..83d55ed
--- /dev/null
+++ b/modules/web-console/frontend/app/modules/Demo/Demo.module.js
@@ -0,0 +1,166 @@
+/*
+ * 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 DEMO_INFO from 'app/data/demo-info.json';
+
+angular
+.module('ignite-console.demo', [
+    'ignite-console.socket'
+])
+.config(['$stateProvider', ($stateProvider) => {
+    $stateProvider
+        .state('demo', {
+            abstract: true,
+            template: '<ui-view></ui-view>'
+        })
+        .state('demo.resume', {
+            url: '/demo',
+            controller: ['$state', ($state) => {
+                $state.go('base.configuration.clusters');
+            }],
+            metaTags: {
+            }
+        })
+        .state('demo.reset', {
+            url: '/demo/reset',
+            controller: ['$state', '$http', 'IgniteMessages', ($state, $http, Messages) => {
+                $http.post('/api/v1/demo/reset')
+                    .success(() => $state.go('base.configuration.clusters'))
+                    .error((err) => {
+                        $state.go('base.configuration.clusters');
+
+                        Messages.showError(err);
+                    });
+            }],
+            metaTags: {}
+        });
+}])
+.provider('Demo', ['$stateProvider', '$httpProvider', 'igniteSocketFactoryProvider', function($state, $http, socketFactory) {
+    if (/(\/demo.*)/ig.test(location.pathname))
+        sessionStorage.setItem('IgniteDemoMode', 'true');
+
+    const enabled = sessionStorage.getItem('IgniteDemoMode') === 'true';
+
+    if (enabled) {
+        socketFactory.set({query: 'IgniteDemoMode=true'});
+
+        $http.interceptors.push('demoInterceptor');
+    }
+
+    this.$get = ['$rootScope', ($root) => {
+        $root.IgniteDemoMode = enabled;
+
+        return {enabled};
+    }];
+}])
+.factory('demoInterceptor', ['Demo', (Demo) => {
+    const isApiRequest = (url) => /\/api\/v1/ig.test(url);
+
+    return {
+        request(cfg) {
+            if (Demo.enabled && isApiRequest(cfg.url))
+                cfg.headers.IgniteDemoMode = true;
+
+            return cfg;
+        }
+    };
+}])
+.controller('demoController', ['$scope', '$state', '$window', 'IgniteConfirm', ($scope, $state, $window, Confirm) => {
+    const _openTab = (stateName) => $window.open($state.href(stateName), '_blank');
+
+    $scope.startDemo = () => {
+        if (!$scope.user.demoCreated)
+            return _openTab('demo.reset');
+
+        Confirm.confirm('Would you like to continue with previous demo session?', true, false)
+            .then((resume) => {
+                if (resume)
+                    return _openTab('demo.resume');
+
+                _openTab('demo.reset');
+            });
+    };
+
+    $scope.closeDemo = () => {
+        $window.close();
+    };
+}])
+.provider('igniteDemoInfo', [function() {
+    const items = DEMO_INFO;
+
+    this.update = (data) => items[0] = data;
+
+    this.$get = [() => {
+        return items;
+    }];
+}])
+.service('DemoInfo', ['$rootScope', '$modal', '$state', '$q', 'igniteDemoInfo', 'IgniteAgentMonitor', ($rootScope, $modal, $state, $q, igniteDemoInfo, agentMonitor) => {
+    const scope = $rootScope.$new();
+
+    let closePromise = null;
+
+    function _fillPage() {
+        const model = igniteDemoInfo;
+
+        scope.title = model[0].title;
+        scope.message = model[0].message.join(' ');
+    }
+
+    const dialog = $modal({
+        templateUrl: '/templates/demo-info.html',
+        scope,
+        placement: 'center',
+        show: false,
+        backdrop: 'static'
+    });
+
+    scope.close = () => {
+        dialog.hide();
+
+        closePromise && closePromise.resolve();
+    };
+
+    scope.downloadAgent = () => {
+        const lnk = document.createElement('a');
+
+        lnk.setAttribute('href', '/api/v1/agent/download/zip');
+        lnk.setAttribute('target', '_self');
+        lnk.setAttribute('download', null);
+        lnk.style.display = 'none';
+
+        document.body.appendChild(lnk);
+
+        lnk.click();
+
+        document.body.removeChild(lnk);
+    };
+
+    return {
+        show: () => {
+            closePromise = $q.defer();
+
+            _fillPage();
+
+            return dialog.$promise
+                .then(dialog.show)
+                .then(() => Promise.race([agentMonitor.awaitAgent(), closePromise.promise]))
+                .then(() => scope.hasAgents = true);
+        }
+    };
+}]);

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/frontend/app/modules/ace.module.js
----------------------------------------------------------------------
diff --git a/modules/web-console/frontend/app/modules/ace.module.js b/modules/web-console/frontend/app/modules/ace.module.js
new file mode 100644
index 0000000..4920a6f
--- /dev/null
+++ b/modules/web-console/frontend/app/modules/ace.module.js
@@ -0,0 +1,269 @@
+/*
+ * 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';
+
+angular
+    .module('ignite-console.ace', [])
+    .constant('igniteAceConfig', {})
+    .directive('igniteAce', ['igniteAceConfig', (aceConfig) => {
+        if (angular.isUndefined(window.ace))
+            throw new Error('ignite-ace need ace to work... (o rly?)');
+
+        /**
+         * Sets editor options such as the wrapping mode or the syntax checker.
+         *
+         * The supported options are:
+         *
+         *   <ul>
+         *     <li>showGutter</li>
+         *     <li>useWrapMode</li>
+         *     <li>onLoad</li>
+         *     <li>theme</li>
+         *     <li>mode</li>
+         *   </ul>
+         *
+         * @param acee
+         * @param session ACE editor session.
+         * @param {object} opts Options to be set.
+         */
+        const setOptions = (acee, session, opts) => {
+            // Sets the ace worker path, if running from concatenated or minified source.
+            if (angular.isDefined(opts.workerPath)) {
+                const config = window.ace.acequire('ace/config');
+
+                config.set('workerPath', opts.workerPath);
+            }
+
+            // Ace requires loading.
+            _.forEach(opts.require, (n) => window.ace.acequire(n));
+
+            // Boolean options.
+            if (angular.isDefined(opts.showGutter))
+                acee.renderer.setShowGutter(opts.showGutter);
+
+            if (angular.isDefined(opts.useWrapMode))
+                session.setUseWrapMode(opts.useWrapMode);
+
+            if (angular.isDefined(opts.showInvisibles))
+                acee.renderer.setShowInvisibles(opts.showInvisibles);
+
+            if (angular.isDefined(opts.showIndentGuides))
+                acee.renderer.setDisplayIndentGuides(opts.showIndentGuides);
+
+            if (angular.isDefined(opts.useSoftTabs))
+                session.setUseSoftTabs(opts.useSoftTabs);
+
+            if (angular.isDefined(opts.showPrintMargin))
+                acee.setShowPrintMargin(opts.showPrintMargin);
+
+            // Commands.
+            if (angular.isDefined(opts.disableSearch) && opts.disableSearch) {
+                acee.commands.addCommands([{
+                    name: 'unfind',
+                    bindKey: {
+                        win: 'Ctrl-F',
+                        mac: 'Command-F'
+                    },
+                    exec: _.constant(false),
+                    readOnly: true
+                }]);
+            }
+
+            // Base options.
+            if (angular.isString(opts.theme))
+                acee.setTheme('ace/theme/' + opts.theme);
+
+            if (angular.isString(opts.mode))
+                session.setMode('ace/mode/' + opts.mode);
+
+            if (angular.isDefined(opts.firstLineNumber)) {
+                if (angular.isNumber(opts.firstLineNumber))
+                    session.setOption('firstLineNumber', opts.firstLineNumber);
+                else if (angular.isFunction(opts.firstLineNumber))
+                    session.setOption('firstLineNumber', opts.firstLineNumber());
+            }
+
+            // Advanced options.
+            if (angular.isDefined(opts.advanced)) {
+                for (const key in opts.advanced) {
+                    if (opts.advanced.hasOwnProperty(key)) {
+                        // Create a javascript object with the key and value.
+                        const obj = {name: key, value: opts.advanced[key]};
+
+                        // Try to assign the option to the ace editor.
+                        acee.setOption(obj.name, obj.value);
+                    }
+                }
+            }
+
+            // Advanced options for the renderer.
+            if (angular.isDefined(opts.rendererOptions)) {
+                for (const key in opts.rendererOptions) {
+                    if (opts.rendererOptions.hasOwnProperty(key)) {
+                        // Create a javascript object with the key and value.
+                        const obj = {name: key, value: opts.rendererOptions[key]};
+
+                        // Try to assign the option to the ace editor.
+                        acee.renderer.setOption(obj.name, obj.value);
+                    }
+                }
+            }
+
+            // onLoad callbacks.
+            _.forEach(opts.callbacks, (cb) => {
+                if (angular.isFunction(cb))
+                    cb(acee);
+            });
+        };
+
+        return {
+            restrict: 'EA',
+            require: ['?ngModel', '?^form'],
+            link: (scope, elm, attrs, [ngModel, form]) => {
+                /**
+                 * Corresponds the igniteAceConfig ACE configuration.
+                 *
+                 * @type object
+                 */
+                const options = aceConfig.ace || {};
+
+                /**
+                 * IgniteAceConfig merged with user options via json in attribute or data binding.
+                 *
+                 * @type object
+                 */
+                let opts = angular.extend({}, options, scope.$eval(attrs.igniteAce));
+
+                /**
+                 * ACE editor.
+                 *
+                 * @type object
+                 */
+                const acee = window.ace.edit(elm[0]);
+
+                /**
+                 * ACE editor session.
+                 *
+                 * @type object
+                 * @see [EditSession]{@link http://ace.c9.io/#nav=api&api=edit_session}
+                 */
+                const session = acee.getSession();
+
+                /**
+                 * Reference to a change listener created by the listener factory.
+                 *
+                 * @function
+                 * @see listenerFactory.onChange
+                 */
+                let onChangeListener;
+
+                /**
+                 * Creates a change listener which propagates the change event and the editor session
+                 * to the callback from the user option onChange.
+                 * It might be exchanged during runtime, if this happens the old listener will be unbound.
+                 *
+                 * @param callback Callback function defined in the user options.
+                 * @see onChangeListener
+                 */
+                const onChangeFactory = (callback) => {
+                    return (e) => {
+                        const newValue = session.getValue();
+
+                        if (ngModel && newValue !== ngModel.$viewValue &&
+                                // HACK make sure to only trigger the apply outside of the
+                                // digest loop 'cause ACE is actually using this callback
+                                // for any text transformation !
+                            !scope.$$phase && !scope.$root.$$phase)
+                            scope.$eval(() => ngModel.$setViewValue(newValue));
+
+                        if (angular.isDefined(callback)) {
+                            scope.$evalAsync(() => {
+                                if (angular.isFunction(callback))
+                                    callback([e, acee]);
+                                else
+                                    throw new Error('ignite-ace use a function as callback');
+                            });
+                        }
+                    };
+                };
+
+                attrs.$observe('readonly', (value) => acee.setReadOnly(!!value || value === ''));
+
+                // Value Blind.
+                if (ngModel) {
+                    // Remove "ngModel" controller from parent form for correct dirty checks.
+                    form && form.$removeControl(ngModel);
+
+                    ngModel.$formatters.push((value) => {
+                        if (angular.isUndefined(value) || value === null)
+                            return '';
+
+                        if (angular.isObject(value) || angular.isArray(value))
+                            throw new Error('ignite-ace cannot use an object or an array as a model');
+
+                        return value;
+                    });
+
+                    ngModel.$render = () => session.setValue(ngModel.$viewValue);
+
+                    acee.on('change', () => ngModel.$setViewValue(acee.getValue()));
+                }
+
+                // Listen for option updates.
+                const updateOptions = (current, previous) => {
+                    if (current === previous)
+                        return;
+
+                    opts = angular.extend({}, options, scope.$eval(attrs.igniteAce));
+
+                    opts.callbacks = [opts.onLoad];
+
+                    // Also call the global onLoad handler.
+                    if (opts.onLoad !== options.onLoad)
+                        opts.callbacks.unshift(options.onLoad);
+
+                    // Unbind old change listener.
+                    session.removeListener('change', onChangeListener);
+
+                    // Bind new change listener.
+                    onChangeListener = onChangeFactory(opts.onChange);
+
+                    session.on('change', onChangeListener);
+
+                    setOptions(acee, session, opts);
+                };
+
+                scope.$watch(attrs.igniteAce, updateOptions, /* deep watch */ true);
+
+                // Set the options here, even if we try to watch later,
+                // if this line is missing things go wrong (and the tests will also fail).
+                updateOptions(options);
+
+                elm.on('$destroy', () => {
+                    acee.session.$stopWorker();
+                    acee.destroy();
+                });
+
+                scope.$watch(() => [elm[0].offsetWidth, elm[0].offsetHeight],
+                    () => {
+                        acee.resize();
+                        acee.renderer.updateFull();
+                    }, true);
+            }
+        };
+    }]);

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/frontend/app/modules/agent/agent.module.js
----------------------------------------------------------------------
diff --git a/modules/web-console/frontend/app/modules/agent/agent.module.js b/modules/web-console/frontend/app/modules/agent/agent.module.js
new file mode 100644
index 0000000..22ced13
--- /dev/null
+++ b/modules/web-console/frontend/app/modules/agent/agent.module.js
@@ -0,0 +1,341 @@
+/*
+ * 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 io from 'socket.io-client'; // eslint-disable-line no-unused-vars
+
+const maskNull = (val) => _.isEmpty(val) ? 'null' : val;
+
+class IgniteAgentMonitor {
+    constructor(socketFactory, $root, $q, $state, $modal, Messages) {
+        this._scope = $root.$new();
+
+        $root.$watch('user', () => {
+            this._scope.user = $root.user;
+        });
+
+        $root.$on('$stateChangeStart', () => {
+            this.stopWatch();
+        });
+
+        // Pre-fetch modal dialogs.
+        this._downloadAgentModal = $modal({
+            scope: this._scope,
+            templateUrl: '/templates/agent-download.html',
+            show: false,
+            backdrop: 'static',
+            keyboard: false
+        });
+
+        const _modalHide = this._downloadAgentModal.hide;
+
+        /**
+         * Special dialog hide function.
+         */
+        this._downloadAgentModal.hide = () => {
+            Messages.hideAlert();
+
+            _modalHide();
+        };
+
+        /**
+         * Close dialog and go by specified link.
+         */
+        this._scope.back = () => {
+            this.stopWatch();
+
+            if (this._scope.backState)
+                this._scope.$$postDigest(() => $state.go(this._scope.backState));
+        };
+
+        this._scope.downloadAgent = () => {
+            const lnk = document.createElement('a');
+
+            lnk.setAttribute('href', '/api/v1/agent/download/zip');
+            lnk.setAttribute('target', '_self');
+            lnk.setAttribute('download', null);
+            lnk.style.display = 'none';
+
+            document.body.appendChild(lnk);
+
+            lnk.click();
+
+            document.body.removeChild(lnk);
+        };
+
+        this._scope.hasAgents = null;
+        this._scope.showModal = false;
+
+        /**
+         * @type {Socket}
+         */
+        this._socket = null;
+
+        this._socketFactory = socketFactory;
+
+        this._$q = $q;
+
+        this.Messages = Messages;
+    }
+
+    /**
+     * @private
+     */
+    checkModal() {
+        if (this._scope.showModal && !this._scope.hasAgents)
+            this._downloadAgentModal.$promise.then(this._downloadAgentModal.show);
+        else if ((this._scope.hasAgents || !this._scope.showModal) && this._downloadAgentModal.$isShown)
+            this._downloadAgentModal.hide();
+    }
+
+    /**
+     * @returns {Promise}
+     */
+    awaitAgent() {
+        if (this._scope.hasAgents)
+            return this._$q.when();
+
+        const latch = this._$q.defer();
+
+        const offConnected = this._scope.$on('agent:watch', (event, state) => {
+            if (state !== 'DISCONNECTED')
+                offConnected();
+
+            if (state === 'CONNECTED')
+                return latch.resolve();
+
+            if (state === 'STOPPED')
+                return latch.reject('Agent watch stopped.');
+        });
+
+        return latch.promise;
+    }
+
+    init() {
+        if (this._socket)
+            return;
+
+        this._socket = this._socketFactory();
+
+        const disconnectFn = () => {
+            this._scope.hasAgents = false;
+
+            this.checkModal();
+
+            this._scope.$broadcast('agent:watch', 'DISCONNECTED');
+        };
+
+        this._socket.on('connect_error', disconnectFn);
+        this._socket.on('disconnect', disconnectFn);
+
+        this._socket.on('agent:count', ({count}) => {
+            this._scope.hasAgents = count > 0;
+
+            this.checkModal();
+
+            this._scope.$broadcast('agent:watch', this._scope.hasAgents ? 'CONNECTED' : 'DISCONNECTED');
+        });
+    }
+
+    /**
+     * @param {Object} back
+     * @returns {Promise}
+     */
+    startWatch(back) {
+        this._scope.backState = back.state;
+        this._scope.backText = back.text;
+
+        this._scope.agentGoal = back.goal;
+
+        if (back.onDisconnect) {
+            this._scope.offDisconnect = this._scope.$on('agent:watch', (e, state) =>
+                state === 'DISCONNECTED' && back.onDisconnect());
+        }
+
+        this._scope.showModal = true;
+
+        // Remove blinking on init.
+        if (this._scope.hasAgents !== null)
+            this.checkModal();
+
+        return this.awaitAgent();
+    }
+
+    /**
+     *
+     * @param {String} event
+     * @param {Object} [args]
+     * @returns {Promise}
+     * @private
+     */
+    _emit(event, ...args) {
+        if (!this._socket)
+            return this._$q.reject('Failed to connect to server');
+
+        const latch = this._$q.defer();
+
+        const onDisconnect = () => {
+            this._socket.removeListener('disconnect', onDisconnect);
+
+            latch.reject('Connection to server was closed');
+        };
+
+        this._socket.on('disconnect', onDisconnect);
+
+        args.push((err, res) => {
+            this._socket.removeListener('disconnect', onDisconnect);
+
+            if (err)
+                latch.reject(err);
+
+            latch.resolve(res);
+        });
+
+        this._socket.emit(event, ...args);
+
+        return latch.promise;
+    }
+
+    drivers() {
+        return this._emit('schemaImport:drivers');
+    }
+
+    /**
+     *
+     * @param {Object} preset
+     * @returns {Promise}
+     */
+    schemas(preset) {
+        return this._emit('schemaImport:schemas', preset);
+    }
+
+    /**
+     *
+     * @param {Object} preset
+     * @returns {Promise}
+     */
+    tables(preset) {
+        return this._emit('schemaImport:tables', preset);
+    }
+
+    /**
+     * @param {Object} err
+     */
+    showNodeError(err) {
+        if (this._scope.showModal) {
+            this._downloadAgentModal.$promise.then(this._downloadAgentModal.show);
+
+            this.Messages.showError(err);
+        }
+    }
+
+    /**
+     *
+     * @param {String} event
+     * @param {Object} [args]
+     * @returns {Promise}
+     * @private
+     */
+    _rest(event, ...args) {
+        return this._downloadAgentModal.$promise
+            .then(() => this._emit(event, ...args));
+    }
+
+    /**
+     * @param {Boolean} [attr]
+     * @param {Boolean} [mtr]
+     * @returns {Promise}
+     */
+    topology(attr, mtr) {
+        return this._rest('node:topology', !!attr, !!mtr);
+    }
+
+    /**
+     * @param {String} nid Node id.
+     * @param {int} [queryId]
+     * @returns {Promise}
+     */
+    queryClose(nid, queryId) {
+        return this._rest('node:query:close', nid, queryId);
+    }
+
+    /**
+     * @param {String} nid Node id.
+     * @param {String} cacheName Cache name.
+     * @param {String} [query] Query if null then scan query.
+     * @param {Boolean} local Flag whether to execute query locally.
+     * @param {int} pageSize
+     * @returns {Promise}
+     */
+    query(nid, cacheName, query, local, pageSize) {
+        return this._rest('node:query', nid, maskNull(cacheName), maskNull(query), local, pageSize)
+            .then(({result}) => {
+                if (_.isEmpty(result.key))
+                    return result.value;
+
+                return Promise.reject(result.key);
+            });
+    }
+
+    /**
+     * @param {String} nid Node id.
+     * @param {String} cacheName Cache name.
+     * @param {String} [query] Query if null then scan query.
+     * @param {Boolean} local Flag whether to execute query locally.
+     * @returns {Promise}
+     */
+    queryGetAll(nid, cacheName, query, local) {
+        return this._rest('node:query:getAll', nid, maskNull(cacheName), maskNull(query), local);
+    }
+
+    /**
+     * @param {String} nid Node id.
+     * @param {int} queryId
+     * @param {int} pageSize
+     * @returns {Promise}
+     */
+    next(nid, queryId, pageSize) {
+        return this._rest('node:query:fetch', nid, queryId, pageSize)
+            .then(({result}) => result);
+    }
+
+    /**
+     * @param {String} [cacheName] Cache name.
+     * @returns {Promise}
+     */
+    metadata(cacheName) {
+        return this._rest('node:cache:metadata', maskNull(cacheName));
+    }
+
+    stopWatch() {
+        this._scope.showModal = false;
+
+        this.checkModal();
+
+        this._scope.offDisconnect && this._scope.offDisconnect();
+
+        this._scope.$broadcast('agent:watch', 'STOPPED');
+    }
+}
+
+IgniteAgentMonitor.$inject = ['igniteSocketFactory', '$rootScope', '$q', '$state', '$modal', 'IgniteMessages'];
+
+angular
+    .module('ignite-console.agent', [
+
+    ])
+    .service('IgniteAgentMonitor', IgniteAgentMonitor);

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/frontend/app/modules/branding/branding.module.js
----------------------------------------------------------------------
diff --git a/modules/web-console/frontend/app/modules/branding/branding.module.js b/modules/web-console/frontend/app/modules/branding/branding.module.js
new file mode 100644
index 0000000..cae7c91
--- /dev/null
+++ b/modules/web-console/frontend/app/modules/branding/branding.module.js
@@ -0,0 +1,45 @@
+/*
+ * 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 IgniteBranding from './branding.provider';
+
+import igniteHeaderLogo from './header-logo.directive';
+import igniteHeaderTitle from './header-title.directive';
+import igniteTerms from './terms.directive';
+import igniteFeatures from './features.directive';
+import igniteFooter from './footer.directive';
+import ignitePoweredByApache from './powered-by-apache.directive';
+
+angular
+.module('ignite-console.branding', [
+    'ui.router.metatags'
+])
+.provider(...IgniteBranding)
+.config(['UIRouterMetatagsProvider', (UIRouterMetatagsProvider) => {
+    UIRouterMetatagsProvider
+        .setDefaultTitle('Apache Ignite - Management Tool and Configuration Wizard')
+        .setTitleSuffix(' \u2013 Apache Ignite Web Console')
+        .setDefaultDescription('The Apache Ignite Web Console is an interactive management tool and configuration wizard which walks you through the creation of config files. Try it now.');
+}])
+.directive(...ignitePoweredByApache)
+.directive(...igniteHeaderLogo)
+.directive(...igniteHeaderTitle)
+.directive(...igniteTerms)
+.directive(...igniteFeatures)
+.directive(...igniteFooter);

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/frontend/app/modules/branding/branding.provider.js
----------------------------------------------------------------------
diff --git a/modules/web-console/frontend/app/modules/branding/branding.provider.js b/modules/web-console/frontend/app/modules/branding/branding.provider.js
new file mode 100644
index 0000000..ce14b34
--- /dev/null
+++ b/modules/web-console/frontend/app/modules/branding/branding.provider.js
@@ -0,0 +1,111 @@
+/*
+ * 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 ['IgniteBranding', [function() {
+    let titleSuffix = ' \u2013 Apache Ignite Web Console';
+
+    let headerLogo = '/images/ignite-logo.png';
+
+    let headerText = 'Management console for Apache Ignite';
+
+    let showIgniteLogo = false;
+
+    let footerHtml = [
+        '<p>Apache Ignite Web Console</p>',
+        '<p>� 2016 The Apache Software Foundation.</p>',
+        '<p>Apache, Apache Ignite, the Apache feather and the Apache Ignite logo are trademarks of The Apache Software Foundation.</p>'
+    ];
+
+    let termsState;
+
+    let featuresHtml = [
+        '<p>Web Console is an interactive management tool which allows to:</p>',
+        '<ul>',
+        '   <li>Create and download cluster configurations</li>',
+        '   <li>Automatically import domain model from any RDBMS</li>',
+        '   <li>Connect to cluster and run SQL analytics on it</li>',
+        '</ul>'
+    ];
+
+    /**
+     * Change title suffix.
+     *
+     * @param {String} suffix.
+     */
+    this.titleSuffix = (suffix) => {
+        titleSuffix = suffix;
+    };
+
+    /**
+     * Change logo in header.
+     *
+     * @param {String} url Logo path.
+     */
+    this.headerLogo = (url) => {
+        headerLogo = url;
+
+        showIgniteLogo = true;
+    };
+
+    /**
+     * Change text in header.
+     *
+     * @param {String} text Header text.
+     */
+    this.headerText = (text) => {
+        headerText = text;
+    };
+
+    /**
+     * Change text in features.
+     *
+     * @param {Array.<String>} rows Features text.
+     */
+    this.featuresHtml = (rows) => {
+        featuresHtml = rows;
+    };
+
+    /**
+     * Change text in footer.
+     *
+     * @param {Array.<String>} rows Footer text.
+     */
+    this.footerHtml = (rows) => {
+        footerHtml = rows;
+    };
+
+    /**
+     * Set terms and conditions stage.
+     *
+     * @param {String} state
+     */
+    this.termsState = (state) => {
+        termsState = state;
+    };
+
+    this.$get = [() => {
+        return {
+            titleSuffix,
+            headerLogo,
+            headerText,
+            featuresHtml: featuresHtml.join('\n'),
+            footerHtml: footerHtml.join('\n'),
+            showIgniteLogo,
+            termsState
+        };
+    }];
+}]];

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/frontend/app/modules/branding/features.directive.js
----------------------------------------------------------------------
diff --git a/modules/web-console/frontend/app/modules/branding/features.directive.js b/modules/web-console/frontend/app/modules/branding/features.directive.js
new file mode 100644
index 0000000..9226a3f
--- /dev/null
+++ b/modules/web-console/frontend/app/modules/branding/features.directive.js
@@ -0,0 +1,35 @@
+/*
+ * 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 template = '<div class="features" ng-bind-html="features.html"></div>';
+
+export default ['igniteFeatures', ['IgniteBranding', (branding) => {
+    function controller() {
+        const ctrl = this;
+
+        ctrl.html = branding.featuresHtml;
+    }
+
+    return {
+        restrict: 'E',
+        template,
+        controller,
+        controllerAs: 'features',
+        replace: true
+    };
+}]];
+

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/frontend/app/modules/branding/footer.directive.js
----------------------------------------------------------------------
diff --git a/modules/web-console/frontend/app/modules/branding/footer.directive.js b/modules/web-console/frontend/app/modules/branding/footer.directive.js
new file mode 100644
index 0000000..f0b1994
--- /dev/null
+++ b/modules/web-console/frontend/app/modules/branding/footer.directive.js
@@ -0,0 +1,34 @@
+/*
+ * 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 template = '<div class="footer" ng-bind-html="footer.html"></div>';
+
+export default ['igniteFooter', ['IgniteBranding', (branding) => {
+    function controller() {
+        const ctrl = this;
+
+        ctrl.html = branding.footerHtml;
+    }
+
+    return {
+        restrict: 'E',
+        template,
+        controller,
+        controllerAs: 'footer',
+        replace: true
+    };
+}]];

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/frontend/app/modules/branding/header-logo.directive.js
----------------------------------------------------------------------
diff --git a/modules/web-console/frontend/app/modules/branding/header-logo.directive.js b/modules/web-console/frontend/app/modules/branding/header-logo.directive.js
new file mode 100644
index 0000000..423de9c
--- /dev/null
+++ b/modules/web-console/frontend/app/modules/branding/header-logo.directive.js
@@ -0,0 +1,34 @@
+/*
+ * 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 templateUrl from './header-logo.jade';
+
+export default ['igniteHeaderLogo', ['IgniteBranding', (branding) => {
+    function controller() {
+        const ctrl = this;
+
+        ctrl.url = branding.headerLogo;
+    }
+
+    return {
+        restrict: 'E',
+        templateUrl,
+        controller,
+        controllerAs: 'logo',
+        replace: true
+    };
+}]];

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/frontend/app/modules/branding/header-logo.jade
----------------------------------------------------------------------
diff --git a/modules/web-console/frontend/app/modules/branding/header-logo.jade b/modules/web-console/frontend/app/modules/branding/header-logo.jade
new file mode 100644
index 0000000..b58f670
--- /dev/null
+++ b/modules/web-console/frontend/app/modules/branding/header-logo.jade
@@ -0,0 +1,18 @@
+//-
+    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.
+
+a(ui-sref='signin')
+    img.navbar-brand(ng-src='{{logo.url}}' height='40')

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/frontend/app/modules/branding/header-title.directive.js
----------------------------------------------------------------------
diff --git a/modules/web-console/frontend/app/modules/branding/header-title.directive.js b/modules/web-console/frontend/app/modules/branding/header-title.directive.js
new file mode 100644
index 0000000..d560e0a
--- /dev/null
+++ b/modules/web-console/frontend/app/modules/branding/header-title.directive.js
@@ -0,0 +1,35 @@
+/*
+ * 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 template = '<h1 class="title">{{::title.text}}</h1>';
+
+export default ['igniteHeaderTitle', ['IgniteBranding', (branding) => {
+    function controller() {
+        const ctrl = this;
+
+        ctrl.text = branding.headerText;
+    }
+
+    return {
+        restrict: 'E',
+        template,
+        controller,
+        controllerAs: 'title',
+        replace: true
+    };
+}]];
+

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/frontend/app/modules/branding/powered-by-apache.directive.js
----------------------------------------------------------------------
diff --git a/modules/web-console/frontend/app/modules/branding/powered-by-apache.directive.js b/modules/web-console/frontend/app/modules/branding/powered-by-apache.directive.js
new file mode 100644
index 0000000..2f02446
--- /dev/null
+++ b/modules/web-console/frontend/app/modules/branding/powered-by-apache.directive.js
@@ -0,0 +1,35 @@
+/*
+ * 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 templateUrl from './powered-by-apache.jade';
+
+export default ['ignitePoweredByApache', ['IgniteBranding', (branding) => {
+    function controller() {
+        const ctrl = this;
+
+        ctrl.show = branding.showIgniteLogo;
+    }
+
+    return {
+        restrict: 'E',
+        templateUrl,
+        controller,
+        controllerAs: 'poweredBy',
+        replace: true
+    };
+}]];
+

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/frontend/app/modules/branding/powered-by-apache.jade
----------------------------------------------------------------------
diff --git a/modules/web-console/frontend/app/modules/branding/powered-by-apache.jade b/modules/web-console/frontend/app/modules/branding/powered-by-apache.jade
new file mode 100644
index 0000000..af9aadf
--- /dev/null
+++ b/modules/web-console/frontend/app/modules/branding/powered-by-apache.jade
@@ -0,0 +1,18 @@
+//-
+    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.
+
+a(ng-if='poweredBy.show' href='//ignite.apache.org' target='_blank')
+    img(ng-src='/images/pb-ignite.png' height='65')

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/frontend/app/modules/branding/terms.directive.js
----------------------------------------------------------------------
diff --git a/modules/web-console/frontend/app/modules/branding/terms.directive.js b/modules/web-console/frontend/app/modules/branding/terms.directive.js
new file mode 100644
index 0000000..0207745
--- /dev/null
+++ b/modules/web-console/frontend/app/modules/branding/terms.directive.js
@@ -0,0 +1,30 @@
+/*
+ * 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 ['igniteTerms', ['IgniteBranding', (branding) => {
+    function controller() {
+        const ctrl = this;
+
+        ctrl.termsState = branding.termsState;
+    }
+
+    return {
+        restrict: 'A',
+        controller,
+        controllerAs: 'terms'
+    };
+}]];

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/frontend/app/modules/configuration/EventGroups.provider.js
----------------------------------------------------------------------
diff --git a/modules/web-console/frontend/app/modules/configuration/EventGroups.provider.js b/modules/web-console/frontend/app/modules/configuration/EventGroups.provider.js
new file mode 100644
index 0000000..61f3188
--- /dev/null
+++ b/modules/web-console/frontend/app/modules/configuration/EventGroups.provider.js
@@ -0,0 +1,30 @@
+/*
+ * 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.
+ */
+
+// Events groups.
+import GROUPS from 'app/data/event-types.json';
+
+export default ['igniteEventGroups', function() {
+    const groups = GROUPS;
+
+    this.push = (data) => groups.push(data);
+
+    this.$get = [() => {
+        return groups;
+    }];
+}];
+

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/frontend/app/modules/configuration/Sidebar.provider.js
----------------------------------------------------------------------
diff --git a/modules/web-console/frontend/app/modules/configuration/Sidebar.provider.js b/modules/web-console/frontend/app/modules/configuration/Sidebar.provider.js
new file mode 100644
index 0000000..8bd5ba3
--- /dev/null
+++ b/modules/web-console/frontend/app/modules/configuration/Sidebar.provider.js
@@ -0,0 +1,39 @@
+/*
+ * 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';
+
+export default ['igniteSidebar', function() {
+    const items = [
+        { text: 'Clusters', sref: 'base.configuration.clusters' },
+        { text: 'Model', sref: 'base.configuration.domains' },
+        { text: 'Caches', sref: 'base.configuration.caches' },
+        { text: 'IGFS', sref: 'base.configuration.igfs' }
+    ];
+
+    this.push = function(data) {
+        items.push(data);
+    };
+
+    this.$get = [function() {
+        const r = angular.copy(items);
+
+        r.push({ text: 'Summary', sref: 'base.configuration.summary' });
+
+        return r;
+    }];
+}];

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/frontend/app/modules/configuration/configuration.module.js
----------------------------------------------------------------------
diff --git a/modules/web-console/frontend/app/modules/configuration/configuration.module.js b/modules/web-console/frontend/app/modules/configuration/configuration.module.js
new file mode 100644
index 0000000..99830b0
--- /dev/null
+++ b/modules/web-console/frontend/app/modules/configuration/configuration.module.js
@@ -0,0 +1,41 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import angular from 'angular';
+
+import igniteEventGroups from './EventGroups.provider';
+import igniteSidebar from './Sidebar.provider';
+
+import GeneratorXml from './generator/Xml.service';
+import GeneratorJava from './generator/Java.service';
+import GeneratorDocker from './generator/Docker.service';
+import GeneratorPom from './generator/Pom.service';
+
+import igniteSidebarDirective from './sidebar.directive';
+
+// Ignite events groups.
+angular
+.module('ignite-console.configuration', [
+
+])
+.provider(...igniteEventGroups)
+.provider(...igniteSidebar)
+.directive(...igniteSidebarDirective)
+.service(...GeneratorXml)
+.service(...GeneratorJava)
+.service(...GeneratorDocker)
+.service(...GeneratorPom);

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/frontend/app/modules/configuration/generator/Docker.service.js
----------------------------------------------------------------------
diff --git a/modules/web-console/frontend/app/modules/configuration/generator/Docker.service.js b/modules/web-console/frontend/app/modules/configuration/generator/Docker.service.js
new file mode 100644
index 0000000..f9776a2
--- /dev/null
+++ b/modules/web-console/frontend/app/modules/configuration/generator/Docker.service.js
@@ -0,0 +1,78 @@
+/*
+ * 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.
+ */
+
+/**
+ * Docker file generation entry point.
+ */
+class GeneratorDocker {
+    /**
+     * Generate from section.
+     *
+     * @param {Object} cluster Cluster.
+     * @param {String} ver Ignite version.
+     * @returns {String}
+     */
+    from(cluster, ver) {
+        return [
+            '# Start from Apache Ignite image.',
+            `FROM apacheignite/ignite:${ver}`
+        ].join('\n');
+    }
+
+    /**
+     * Generate Docker file for cluster.
+     *
+     * @param {Object} cluster Cluster.
+     * @param {String} ver Ignite version.
+     */
+    generate(cluster, ver) {
+        return [
+            this.from(cluster, ver),
+            '',
+            '# Set config uri for node.',
+            `ENV CONFIG_URI config/${cluster.name}-server.xml`,
+            '',
+            '# Copy ignite-http-rest from optional.',
+            'ENV OPTION_LIBS ignite-rest-http',
+            '',
+            '# Update packages and install maven.',
+            'RUN \\',
+            '   apt-get update &&\\',
+            '   apt-get install -y maven',
+            '',
+            '# Append project to container.',
+            `ADD . ${cluster.name}`,
+            '',
+            '# Build project in container.',
+            `RUN mvn -f ${cluster.name}/pom.xml clean package -DskipTests`,
+            '',
+            '# Copy project jars to node classpath.',
+            `RUN mkdir $IGNITE_HOME/libs/${cluster.name} && \\`,
+            `   find ${cluster.name}/target -name "*.jar" -type f -exec cp {} $IGNITE_HOME/libs/${cluster.name} \\; && \\`,
+            `   cp -r ${cluster.name}/config/* $IGNITE_HOME/config`
+        ].join('\n');
+    }
+
+    ignoreFile() {
+        return [
+            'target',
+            'Dockerfile'
+        ].join('\n');
+    }
+}
+
+export default ['GeneratorDocker', GeneratorDocker];

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/frontend/app/modules/configuration/generator/Java.service.js
----------------------------------------------------------------------
diff --git a/modules/web-console/frontend/app/modules/configuration/generator/Java.service.js b/modules/web-console/frontend/app/modules/configuration/generator/Java.service.js
new file mode 100644
index 0000000..67e19b9
--- /dev/null
+++ b/modules/web-console/frontend/app/modules/configuration/generator/Java.service.js
@@ -0,0 +1,21 @@
+/*
+ * 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.
+ */
+
+// TODO IGNITE-2054: need move $generatorJava to services.
+export default ['GeneratorJava', () => {
+    return $generatorJava;
+}];


[23/52] ignite git commit: Web Console beta-3.

Posted by ak...@apache.org.
http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/frontend/views/configuration/domains.jade
----------------------------------------------------------------------
diff --git a/modules/web-console/frontend/views/configuration/domains.jade b/modules/web-console/frontend/views/configuration/domains.jade
new file mode 100644
index 0000000..5912343
--- /dev/null
+++ b/modules/web-console/frontend/views/configuration/domains.jade
@@ -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.
+
+include ../../app/helpers/jade/mixins.jade
+
+.docs-header
+    h1 Configure Domain Model And SQL Queries
+.docs-body(ng-controller='domainsController')
+    ignite-information
+        ul: li Import database schemas
+            li Configure indexed types
+    div(ignite-loading='loadingDomainModelsScreen' ignite-loading-text='Loading domain models...' ignite-loading-position='top')
+        div(ng-show='ui.ready')
+            hr
+            .padding-bottom-dflt(ng-show='domains && domains.length > 0')
+                table.links(st-table='displayedRows' st-safe-src='domains')
+                    thead
+                        tr
+                            th
+                                .col-sm-9
+                                    .col-sm-6
+                                        lable.labelHeader.labelFormField {{domainModelTitle()}}
+                                    .col-sm-6
+                                        .pull-right.labelLogin.additional-filter(ng-if='(domains | domainsValidation:false:true).length > 0')
+                                            a.labelFormField(ng-if='ui.showValid' ng-click='toggleValid()' bs-tooltip='' data-title='{{::ui.invalidKeyFieldsTooltip}}') Key fields should be configured: {{(displayedRows | domainsValidation:false:true).length}}&nbsp
+                                            a.labelFormField(ng-if='!ui.showValid' ng-click='toggleValid()') Show all domain models: {{displayedRows.length}}&nbsp
+                                .col-sm-3
+                                    input.form-control.pull-right(type='text' st-search='valueType' placeholder='Filter domain models...')
+                        tbody
+                            tr
+                                td
+                                    .scrollable-y(ng-show='(displayedRows | domainsValidation:ui.showValid:true).length > 0' style='max-height: 200px')
+                                        table
+                                            tbody
+                                                tr(ng-repeat='row in (displayedRows | domainsValidation:ui.showValid:true) track by row._id' ignite-bs-affix-update)
+                                                    td
+                                                        a(ng-class='{active: row._id == selectedItem._id}' ng-click='selectItem(row)') {{$index + 1}}) {{row.valueType}}
+                                    label.placeholder(ng-show='(displayedRows | domainsValidation:ui.showValid:true).length == 0') No domain models found
+            .padding-top-dflt(bs-affix)
+                .panel-tip-container(data-placement='bottom' bs-tooltip='' data-title='Create new domain model')
+                    button.btn.btn-primary(id='new-item' ng-click='createItem()') Add domain model
+                .panel-tip-container(bs-tooltip='' data-title='Import domain models from database' data-placement='bottom')
+                    button.btn.btn-primary(ng-click='showImportDomainModal()') Import from database
+                +save-remove-clone-undo-buttons('domain model')
+                .btn-group.panel-tip-container.pull-right(bs-tooltip='' data-title='Import domain models from demo database' data-placement='bottom')
+                hr
+            .bs-affix-fix
+            div(bs-collapse='' data-allow-multiple='true' ng-model='ui.activePanels')
+                form.form-horizontal(name='ui.inputForm' novalidate ng-if='contentVisible()')
+                    .panel-group
+                        include ../../app/modules/states/configuration/domains/general.jade
+                        include ../../app/modules/states/configuration/domains/query.jade
+                        include ../../app/modules/states/configuration/domains/store.jade

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/frontend/views/configuration/igfs.jade
----------------------------------------------------------------------
diff --git a/modules/web-console/frontend/views/configuration/igfs.jade b/modules/web-console/frontend/views/configuration/igfs.jade
new file mode 100644
index 0000000..16e9f28
--- /dev/null
+++ b/modules/web-console/frontend/views/configuration/igfs.jade
@@ -0,0 +1,51 @@
+//-
+    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.jade
+
+.docs-header
+    h1 Configure Ignite In-memory File Systems
+.docs-body(ng-controller='igfsController')
+    ignite-information(data-title='Configure IGFS only if you are going to use In-memory File System')
+        ul
+            li Ignite File System (#[a(href='https://apacheignite-fs.readme.io/docs/in-memory-file-system' target='_blank') IGFS]) is an in-memory file system allowing work with files and directories over existing cache infrastructure
+            li IGFS can either work as purely in-memory file system, or delegate to another file system (e.g. various Hadoop file system implementations) acting as a caching layer (see #[a(href='https://apacheignite-fs.readme.io/docs/secondary-file-system' target='_blank') secondary file system]  for more detail)
+            li In addition IGFS provides API to execute map-reduce tasks over file system data
+    div(ignite-loading='loadingIgfsScreen' ignite-loading-text='Loading IGFS screen...' ignite-loading-position='top')
+        div(ng-show='ui.ready')
+            hr
+            +main-table('IGFS', 'igfss', 'igfsName', 'selectItem(row)', '{{$index + 1}}) {{row.name}}', 'name')
+            .padding-top-dflt(bs-affix)
+                .panel-tip-container(data-placement='bottom' bs-tooltip='' data-title='Create new IGFS')
+                    button.btn.btn-primary(id='new-item' ng-click='createItem()') Add IGFS
+                +save-remove-clone-undo-buttons('IGFS')
+                hr
+            .bs-affix-fix
+            div(bs-collapse='' data-allow-multiple='true' ng-model='ui.activePanels')
+                form.form-horizontal(name='ui.inputForm' novalidate ng-if='contentVisible()')
+                    .panel-group
+                        include ../../app/modules/states/configuration/igfs/general.jade
+
+                        +advanced-options-toggle-default
+
+                        div(ng-show='ui.expanded')
+                            include ../../app/modules/states/configuration/igfs/secondary.jade
+                            include ../../app/modules/states/configuration/igfs/ipc.jade
+                            include ../../app/modules/states/configuration/igfs/fragmentizer.jade
+                            include ../../app/modules/states/configuration/igfs/dual.jade
+                            include ../../app/modules/states/configuration/igfs/misc.jade
+
+                            +advanced-options-toggle-default

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/frontend/views/configuration/sidebar.jade
----------------------------------------------------------------------
diff --git a/modules/web-console/frontend/views/configuration/sidebar.jade b/modules/web-console/frontend/views/configuration/sidebar.jade
new file mode 100644
index 0000000..bba6b25
--- /dev/null
+++ b/modules/web-console/frontend/views/configuration/sidebar.jade
@@ -0,0 +1,29 @@
+//-
+    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.
+
+.row
+    .col-xs-3.col-sm-3.col-md-2.border-right.section-left.greedy
+        .sidebar-nav(bs-affix)
+            ul.menu(ignite-sidebar)
+                li(ng-repeat='item in sidebar.items')
+                    a(ui-sref-active='active' ui-sref='{{::item.sref}}')
+                        span.fa-stack
+                            i.fa.fa-circle-thin.fa-stack-2x
+                            i.fa.fa-stack-1x {{::$index + 1}}
+                        | {{::item.text}}
+
+    .col-xs-9.col-sm-9.col-md-10.border-left.section-right
+        .docs-content(ui-view='')

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/frontend/views/configuration/summary-project-structure.jade
----------------------------------------------------------------------
diff --git a/modules/web-console/frontend/views/configuration/summary-project-structure.jade b/modules/web-console/frontend/views/configuration/summary-project-structure.jade
new file mode 100644
index 0000000..aa09437
--- /dev/null
+++ b/modules/web-console/frontend/views/configuration/summary-project-structure.jade
@@ -0,0 +1,27 @@
+//-
+    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.
+.popover.summary-project-structure
+    h3.popover-title
+        label.labelField Project structure
+        button.close(id='summary-project-structure-close' ng-click='$hide()') &times;
+    .popover-content
+        treecontrol.tree-classic(tree-model='projectStructure' options='projectStructureOptions' expanded-nodes='projectStructureExpanded')
+            span(ng-switch='' on='node.type')
+                span(ng-switch-when='folder')
+                    label {{node.name}}
+                span(ng-switch-when='file')
+                    i.fa.fa-file-text-o
+                    label {{node.name}}

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/frontend/views/configuration/summary-tabs.jade
----------------------------------------------------------------------
diff --git a/modules/web-console/frontend/views/configuration/summary-tabs.jade b/modules/web-console/frontend/views/configuration/summary-tabs.jade
new file mode 100644
index 0000000..847b42f
--- /dev/null
+++ b/modules/web-console/frontend/views/configuration/summary-tabs.jade
@@ -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.
+
+ul.nav(ng-class='$navClass', role='tablist')
+    li(role='presentation' ng-repeat='$pane in $panes track by $index' ng-class='[ $isActive($pane, $index) ? $activeClass : "", $pane.disabled ? "disabled" : "" ]')
+        a.summary-tab(ng-show='$pane.title != "POJO" || (cluster | hasPojo)' ng-switch='$pane.title' role='tab' data-toggle='tab' ng-click='!$pane.disabled && $setActive($pane.name || $index)' data-index='{{ $index }}' aria-controls='$pane.title') {{$pane.title}}
+            img(ng-switch-when='XML' src='/images/xml.png')
+            img(ng-switch-when='Java' src='/images/java.png')
+            img(ng-switch-when='POM' src='/images/xml.png')
+            img(ng-switch-when='POJO' src='/images/java.png')
+            img(ng-switch-when='Dockerfile' src='/images/docker.png')
+.tab-content(ng-transclude style='fontSize: 12px; min-height: 25em')

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/frontend/views/configuration/summary.jade
----------------------------------------------------------------------
diff --git a/modules/web-console/frontend/views/configuration/summary.jade b/modules/web-console/frontend/views/configuration/summary.jade
new file mode 100644
index 0000000..0d30df8
--- /dev/null
+++ b/modules/web-console/frontend/views/configuration/summary.jade
@@ -0,0 +1,122 @@
+//-
+    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.jade
+
+mixin hard-link(ref, txt)
+    a(style='color:#ec1c24' href=ref target='_blank') #{txt}
+
+.docs-header
+    h1 Configurations Summary
+.docs-body
+    ignite-information
+        ul
+            li Preview XML configurations for #[a(href='https://apacheignite.readme.io/docs/clients-vs-servers' target='_blank') server and client] nodes
+            li Preview code configuration
+            li Preview #[a(href='https://apacheignite.readme.io/docs/docker-deployment' target='_blank') Docker file]
+            li Preview POM dependencies
+            li Download ready-to-use Maven project
+
+    hr
+    .padding-dflt(ng-if='ui.ready && (!clusters || clusters.length == 0)')
+        | You have no clusters configured. Please configure them #[a(ui-sref='base.configuration.clusters') here].
+
+    div(ng-show='clusters && clusters.length > 0' ignite-loading='summaryPage' ignite-loading-text='Loading summary screen...' ignite-loading-position='top')
+        +main-table('clusters', 'clustersView', 'clusterName', 'selectItem(row)', '{{$index + 1}}) {{row.name}}', 'name')
+        div(ng-show='selectedItem && contentVisible(displayedRows, selectedItem)')
+            .padding-top-dflt(bs-affix)
+                button.btn.btn-primary(id='download' ng-click='downloadConfiguration()' bs-tooltip='' data-title='Download project' data-placement='bottom') Download project
+                .btn.btn-primary(bs-tooltip='' data-title='Preview generated project structure' data-placement='bottom')
+                    div(bs-popover data-template-url='/configuration/summary-project-structure.html', data-placement='bottom', data-trigger='click' data-auto-close='true')
+                        i.fa.fa-sitemap
+                        label.tipLabel Project structure
+                button.btn.btn-primary(id='proprietary-jdbc-drivers' ng-if='downloadJdbcDriversVisible()' ng-click='downloadJdbcDrivers()' bs-tooltip='' data-title='Open proprietary JDBC drivers download pages' data-placement='bottom') Download JDBC drivers
+                hr
+            .bs-affix-fix
+            .panel-group(bs-collapse ng-init='ui.activePanels=[0,1]' ng-model='ui.activePanels' data-allow-multiple='true')
+                .panel.panel-default
+                    .panel-heading(role='tab' bs-collapse-toggle)
+                        ignite-form-panel-chevron
+                        label Server
+
+                    .panel-collapse(id='server' role='tabpanel' bs-collapse-target)
+                        ignite-ui-ace-tabs.summary-tabs
+                            div(bs-tabs data-bs-active-pane="tabsServer.activeTab" template='configuration/summary-tabs.html')
+                                div(bs-pane title='XML')
+                                    ignite-ui-ace-xml(ng-if='tabsServer.activeTab == 0 || tabsServer.init[0]' ng-init='tabsServer.init[0] = true' data-master='cluster' data-no-deep-watch)
+                                div(bs-pane title='Java')
+                                    ignite-ui-ace-java(ng-if='tabsServer.activeTab == 1 || tabsServer.init[1]' ng-init='tabsServer.init[1] = true' data-master='cluster' data-no-deep-watch)
+                                div(bs-pane title='POM')
+                                    ignite-ui-ace-pom(ng-if='tabsServer.activeTab == 2 || tabsServer.init[2]' ng-init='tabsServer.init[2] = true' data-cluster='cluster' data-no-deep-watch)
+                                div(bs-pane title='Dockerfile')
+                                    ignite-ui-ace-docker(ng-if='tabsServer.activeTab == 3 || tabsServer.init[3]' ng-init='tabsServer.init[3] = true' data-cluster='cluster' data-no-deep-watch ng-model='ctrl.data.docker')
+
+                .panel.panel-default
+                    .panel-heading(role='tab' bs-collapse-toggle)
+                        ignite-form-panel-chevron
+                        label Client
+
+                    .panel-collapse(id='client' role='tabpanel' bs-collapse-target)
+                        -var form = 'clientForm'
+                        form(name=form novalidate)
+                            -var nearCfg = 'ctrl.cluster.clientNearCfg'
+                            -var nearCfgEvictionPolicy = nearCfg + '.nearEvictionPolicy[' + nearCfg + '.nearEvictionPolicy.kind]'
+
+                            .group-content
+                                .settings-row(ng-if='true')
+                                    .col-xs-8.col-sm-8.col-md-7
+                                        +ignite-form-field-number('Near cache start size:', nearCfg + '.nearStartSize', '"nearStartSize"', false, false, '375000', false, false, false, 'Initial cache size for near cache which will be used to pre-create internal hash table after start')
+
+                                .settings-row(ng-if='true')
+                                    .col-xs-8.col-sm-8.col-md-7
+                                        +ignite-form-field-dropdown('Near cache eviction policy', nearCfg + '.nearEvictionPolicy.kind', '"evictionPolicies"', false, false, false, 'Not set', false, '[\
+                                                {value: "LRU", label: "LRU"},\
+                                                {value: "FIFO", label: "FIFO"},\
+                                                {value: "SORTED", label: "Sorted"},\
+                                                {value: undefined, label: "Not set"}\
+                                            ]', 'Near cache eviction policy')
+
+                                    span(ng-if='#{nearCfg}.nearEvictionPolicy.kind')
+                                        a.customize(
+                                            ng-show='ctrl.__form.expanded'
+                                            ng-click='ctrl.__form.expanded = false'
+                                        ) Hide settings
+                                        a.customize(
+                                            ng-hide='ctrl.__form.expanded'
+                                            ng-click='ctrl.__form.expanded = true'
+                                        ) Show settings
+
+                                .settings-row
+                                    .panel-details.col-xs-12.col-sm-12.col-md-7(ng-if='ctrl.__form.expanded && #{nearCfg}.nearEvictionPolicy.kind')
+                                        .details-row
+                                            +ignite-form-field-number('Batch size:', nearCfgEvictionPolicy + '.batchSize', '"batchSize"', false, false, '1', false, false, false, 'Number of entries to remove on shrink')
+
+                                        .details-row
+                                            +ignite-form-field-number('Max memory size:', nearCfgEvictionPolicy + '.maxMemorySize', '"maxMemorySize"', false, false, '0', false, false, false, 'Maximum allowed cache size in bytes')
+
+                                        .details-row
+                                            +ignite-form-field-number('Max size:', nearCfgEvictionPolicy + '.maxSize', '"maxSize"', false, false, '100000', false, false, false, 'Maximum allowed size of cache before entry will start getting evicted')
+
+                        .summary-tabs(ignite-ui-ace-tabs)
+                            div(bs-tabs data-bs-active-pane="tabsClient.activeTab" template='configuration/summary-tabs.html')
+                                div(bs-pane title='XML')
+                                    ignite-ui-ace-xml(ng-if='tabsClient.activeTab == 0 || tabsClient.init[0]' ng-init='tabsClient.init[0] = true' data-master='cluster' data-no-deep-watch data-cluster-cfg='#{nearCfg}')
+                                div(bs-pane title='Java')
+                                    ignite-ui-ace-java(ng-if='tabsClient.activeTab == 1 || tabsClient.init[1]' ng-init='tabsClient.init[1] = true' data-master='cluster' data-no-deep-watch data-cluster-cfg='#{nearCfg}')
+                                div(bs-pane title='POM')
+                                    ignite-ui-ace-pom(ng-if='tabsClient.activeTab == 2 || tabsClient.init[2]' ng-init='tabsClient.init[2] = true' data-cluster='cluster' data-no-deep-watch)
+                                div(bs-pane title='POJO' ng-if='cluster | hasPojo')
+                                    ignite-ui-ace-pojos(ng-if='tabsClient.activeTab == 3 || tabsClient.init[3]' ng-init='tabsClient.init[3] = true' data-cluster='cluster' data-no-deep-watch ng-model='ctrl.data.pojos')

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/frontend/views/includes/footer.jade
----------------------------------------------------------------------
diff --git a/modules/web-console/frontend/views/includes/footer.jade b/modules/web-console/frontend/views/includes/footer.jade
new file mode 100644
index 0000000..4ef3bf6
--- /dev/null
+++ b/modules/web-console/frontend/views/includes/footer.jade
@@ -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.
+
+.container.container-footer
+    footer
+        .col-md-offset-1.col-md-10
+            ignite-footer
+        .col-md-1
+            .pull-right
+                ignite-powered-by-apache

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/frontend/views/includes/header.jade
----------------------------------------------------------------------
diff --git a/modules/web-console/frontend/views/includes/header.jade b/modules/web-console/frontend/views/includes/header.jade
new file mode 100644
index 0000000..9ef09aa
--- /dev/null
+++ b/modules/web-console/frontend/views/includes/header.jade
@@ -0,0 +1,51 @@
+//-
+    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.
+
+header#header.header
+    .viewedUser(ng-show='$root.user.becomeUsed')
+        | Currently assuming #[strong {{$root.user.firstName}} {{$root.user.lastName}}], #[a(ng-click='$root.revertIdentity()') revert to your identity].
+    table.container
+        tr
+            td.col-xs-3.col-sm-3.col-md-2
+                ignite-header-logo
+            td(ng-if='$root.user' style='padding-top: 20px')
+                ul.nav.navbar-nav(ignite-sidebar ignite-navbar)
+                    li(ng-class='{active: $state.includes("base.configuration")}' bs-dropdown='sidebar.items' data-placement='bottom-right' data-trigger='hover focus' data-container='self' data-animation='' ng-click='$event.stopPropagation()')
+                        a.dropdown-toggle Configuration
+                            span.caret
+
+                ul.nav.navbar-nav(ng-controller='notebookController')
+                    li.sql-notebooks(ng-if='IgniteDemoMode' ng-class='{active: $state.includes("base.sql")}')
+                        a(ui-sref='base.sql.demo') SQL
+
+                    li.sql-notebooks(ng-if='!IgniteDemoMode && !notebooks.length' ng-class='{active: $state.includes("base.sql")}')
+                        a(ng-click='createNotebook()') SQL
+
+                    li.sql-notebooks(ng-if='!IgniteDemoMode && notebooks.length' ng-class='{active: $state.includes("base.sql")}' bs-dropdown='notebooks' data-placement='bottom-left' data-trigger='hover focus' data-container='self' data-animation='' ng-click='$event.stopPropagation()' aria-haspopup="true" aria-expanded="false")
+                        a.dropdown-toggle SQL
+                            span.caret
+
+                    li(ui-sref-active='active'  ng-repeat='item in navbar.items')
+                        a(ui-sref='{{::item.sref}}') {{::item.text}}
+
+                a(ng-controller='demoController')
+                    button.btn.btn-info(ng-if='IgniteDemoMode' ng-click='closeDemo()') Close demo
+                    button.btn.btn-info(ng-if='!IgniteDemoMode' ng-click='startDemo()') Start demo
+
+                ul.nav.navbar-nav.pull-right(ignite-userbar)
+                    li(bs-dropdown='userbar.items' data-placement='bottom-right' data-trigger='hover focus' data-container='self' data-animation='' ng-class='{active: $state.includes("settings")}' ng-click='$event.stopPropagation()')
+                        a.dropdown-toggle {{user.firstName}} {{user.lastName}}
+                            span.caret

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/frontend/views/index.jade
----------------------------------------------------------------------
diff --git a/modules/web-console/frontend/views/index.jade b/modules/web-console/frontend/views/index.jade
new file mode 100644
index 0000000..c561c3e
--- /dev/null
+++ b/modules/web-console/frontend/views/index.jade
@@ -0,0 +1,47 @@
+//-
+    Licensed to the Apache Software Foundation (ASF) under one or more
+    contributor license agreements.  See the NOTICE file distributed with
+    this work for additional information regarding copyright ownership.
+    The ASF licenses this file to You under the Apache License, Version 2.0
+    (the "License"); you may not use this file except in compliance with
+    the License.  You may obtain a copy of the License at
+
+         http://www.apache.org/licenses/LICENSE-2.0
+
+    Unless required by applicable law or agreed to in writing, software
+    distributed under the License is distributed on an "AS IS" BASIS,
+    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    See the License for the specific language governing permissions and
+    limitations under the License.
+
+doctype html
+html(ng-app='ignite-console' id='app' ng-strict-di)
+    head
+        base(href='/')
+
+        meta(http-equiv='content-type' content='text/html; charset=UTF8')
+        meta(http-equiv='content-language' content='en')
+
+        title(ng-bind='$meta.title')
+
+        meta(name='fragment' content='!')
+        meta(name='description' content='{{$meta.description}}')
+        meta(name='keywords' content='{{$meta.keywords}}')
+        meta(ng-repeat='(key, value) in $meta.properties' name='{{::key}}' content='{{::value}}')
+
+    body.theme-line.body-overlap.greedy
+
+        .splash.splash-max-foreground(hide-on-state-change)
+            .splash-wrapper
+                .spinner
+                    .bounce1
+                    .bounce2
+                    .bounce3
+
+                .splash-wellcome Loading...
+
+        .ribbon-wrapper.right(ng-cloak)
+            .ribbon(ng-style='IgniteDemoMode && {"background": "#1b6d88"}')
+                label {{IgniteDemoMode ? "Demo" : "Beta" }}
+
+        .wrapper(ui-view='')

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/frontend/views/reset.jade
----------------------------------------------------------------------
diff --git a/modules/web-console/frontend/views/reset.jade b/modules/web-console/frontend/views/reset.jade
new file mode 100644
index 0000000..9098105
--- /dev/null
+++ b/modules/web-console/frontend/views/reset.jade
@@ -0,0 +1,48 @@
+//-
+    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.
+
+header#header.header
+    table.container
+        tr
+            td.col-xs-3.col-sm-3.col-md-2
+                ignite-header-logo
+            td
+                ignite-header-title
+
+.container.body-container
+    .main-content(ng-controller='resetPassword')
+        .row
+            .text-center(ng-if='!token')
+                p Further instructions for password reset have been sent to your e-mail address.
+            .text-center(ng-if='error')
+                p {{::error}}
+            div(ng-if='token && !error')
+                form.form-horizontal(name='resetForm' ng-init='reset_info.token = token')
+                    .settings-row
+                        label.col-sm-1 E-mail:
+                        label {{::email}}
+                    .settings-row
+                        label.col-sm-1.required Password:
+                        .col-sm-3
+                            input#user_password.form-control(ignite-on-enter-focus-move='user_confirm' type='password' ng-model='reset_info.password' placeholder='New password' required)
+                    .settings-row
+                        label.col-sm-1.required Confirm:
+                        .col-sm-3
+                            input#user_confirm.form-control(type='password' ng-model='reset_info.confirm' ignite-match='reset_info.password' placeholder='Confirm new password' required ignite-on-enter='resetForm.$valid && resetPassword(user_info)')
+                    .settings-row
+                        button.btn.btn-primary(ng-disabled='resetForm.$invalid' ng-click='resetPassword(reset_info)') Reset Password
+
+include includes/footer

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/frontend/views/settings/admin.jade
----------------------------------------------------------------------
diff --git a/modules/web-console/frontend/views/settings/admin.jade b/modules/web-console/frontend/views/settings/admin.jade
new file mode 100644
index 0000000..862d959
--- /dev/null
+++ b/modules/web-console/frontend/views/settings/admin.jade
@@ -0,0 +1,76 @@
+//-
+    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.
+
+.row(ng-controller='adminController')
+    .docs-content.greedy
+        .docs-header
+            h1 List of registered users
+            hr
+        .docs-body
+            .col-xs-12
+                table.table.table-striped.table-vertical-middle.admin(st-table='displayedUsers' st-safe-src='users')
+                    thead
+                        tr
+                            th.header(colspan='10')
+                                .col-xs-3
+                                    input.form-control(type='text' st-search='label' placeholder='Filter users...')
+                                .col-xs-9.admin-summary.text-right(colspan='10')
+                                    strong Total users: {{ users.length }}
+                                .col-xs-offset-6.col-xs-6.text-right
+                                    div(st-pagination st-items-by-page='15' st-displayed-pages='5' st-template='../templates/pagination.html')
+                        tr
+                            th(st-sort='userName') User
+                            th(st-sort='email') Email
+                            th(st-sort='company') Company
+                            th(st-sort='country') Country
+                            th.col-xs-2(st-sort='lastLogin' st-sort-default='reverse') Last login
+                            th.text-nowrap(st-sort='counters.clusters' st-descending-first bs-tooltip='"Clusters count"' data-placement='top')
+                                i.fa.fa-sitemap()
+                            th.text-nowrap(st-sort='counters.models' st-descending-first bs-tooltip='"Models count"' data-placement='top')
+                                i.fa.fa-object-group()
+                            th.text-nowrap(st-sort='counters.caches' st-descending-first bs-tooltip='"Caches count"' data-placement='top')
+                                i.fa.fa-database()
+                            th.text-nowrap(st-sort='counters.igfs' st-descending-first bs-tooltip='"IGFS count"' data-placement='top')
+                                i.fa.fa-folder-o()
+                            th(width='1%') Actions
+                    tbody
+                        tr(ng-repeat='row in displayedUsers track by row._id')
+                            td {{::row.userName}}
+                            td
+                                a(ng-href='mailto:{{::row.email}}') {{::row.email}}
+                            td {{::row.company}}
+                            td {{::row.countryCode}}
+                            td {{::row.lastLogin | date:'medium'}}
+                            td {{::row.counters.clusters}}
+                            td {{::row.counters.models}}
+                            td {{::row.counters.caches}}
+                            td {{::row.counters.igfs}}
+                            td.text-center
+                                a.btn.btn-default.dropdown-toggle(bs-dropdown='' ng-show='row._id != user._id' data-placement='bottom-right')
+                                    i.fa.fa-gear &nbsp;
+                                    span.caret
+                                ul.dropdown-menu(role='menu')
+                                    li
+                                        a(ng-click='becomeUser(row)') Become this user
+                                    li
+                                        a(ng-click='toggleAdmin(row)' ng-if='row.admin && row._id !== user._id') Revoke admin
+                                        a(ng-click='toggleAdmin(row)' ng-if='!row.admin && row._id !== user._id')  Grant admin
+                                    li
+                                        a(ng-click='removeUser(row)') Remove user
+                    tfoot
+                        tr
+                            td.text-right(colspan='10')
+                                div(st-pagination st-items-by-page='15' st-displayed-pages='5' st-template='../templates/pagination.html')

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/frontend/views/settings/profile.jade
----------------------------------------------------------------------
diff --git a/modules/web-console/frontend/views/settings/profile.jade b/modules/web-console/frontend/views/settings/profile.jade
new file mode 100644
index 0000000..bc4965a
--- /dev/null
+++ b/modules/web-console/frontend/views/settings/profile.jade
@@ -0,0 +1,76 @@
+//-
+    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.
+
+mixin lbl(txt)
+    label.col-sm-2.required.labelFormField #{txt}
+
+.row(ng-controller='profileController')
+    .docs-content.greedy
+        .docs-header
+            h1 User profile
+            hr
+        .docs-body
+            form.form-horizontal(name='profileForm' novalidate)
+                .col-sm-10(style='padding: 0')
+                    .details-row
+                        +lbl('First name:')
+                        .col-xs-5.col-sm-4
+                            input#profile-firstname.form-control(ignite-on-enter-focus-move='profile-lastname' type='text' ng-model='user.firstName' placeholder='Input first name' required ignite-auto-focus)
+                    .details-row
+                        +lbl('Last name:')
+                        .col-xs-5.col-sm-4
+                            input#profile-lastname.form-control(ignite-on-enter-focus-move='profile-email' type='text' ng-model='user.lastName' placeholder='Input last name' required)
+                    .details-row
+                        +lbl('Email:')
+                        .col-xs-5.col-sm-4
+                            input#profile-email.form-control(ignite-on-enter-focus-move='profile-company' type='email' ng-model='user.email' placeholder='Input email' required)
+                    .details-row
+                        +lbl('Company:')
+                        .col-xs-5.col-sm-4
+                            input#profile-company.form-control(ignite-on-enter-focus-move='profile-country' type='text' ng-model='user.company' placeholder='Input company name' required)
+                    .details-row
+                        +lbl('Country:')
+                        .col-xs-5.col-sm-4
+                            button#profile-country.select-toggle.form-control(bs-select bs-options='item.name as item.name for item in countries' type='text' ng-model='user.country' placeholder='Choose your country' ng-required='true')
+                    .details-row
+                        .advanced-options
+                            i.fa(
+                            ng-click='toggleToken()'
+                            ng-class='expandedToken ? "fa-chevron-circle-down" : "fa-chevron-circle-right"')
+                            a(ng-click='toggleToken()') {{expandedToken ? 'Cancel security token changing...' : 'Show security token...'}}
+                        div(ng-if='expandedToken')
+                            +lbl('Security token:')
+                            label {{user.token || 'No security token. Regenerate please.'}}
+                            i.tipLabel.fa.fa-refresh(ng-click='generateToken()' bs-tooltip='' data-title='Generate random security token')
+                            i.tipLabel.fa.fa-clipboard(ignite-copy-to-clipboard='{{user.token}}' bs-tooltip='' data-title='Copy security token to clipboard')
+                            i.tipLabel.fa.fa-question-circle(ng-if=lines bs-tooltip='' data-title='The security token is used for authorization of web agent')
+                    .details-row
+                        .advanced-options
+                            i.fa(
+                            ng-click='togglePassword()'
+                            ng-class='expandedPassword ? "fa-chevron-circle-down" : "fa-chevron-circle-right"')
+                            a(ng-click='togglePassword()') {{expandedPassword ? 'Cancel password changing...' : 'Change password...'}}
+                        div(ng-if='expandedPassword')
+                            .details-row
+                                +lbl('New password:')
+                                .col-xs-5.col-sm-4
+                                    input#profile_password.form-control(ignite-on-enter-focus-move='profile_confirm' type='password' ng-model='user.password' placeholder='New password')
+                            .details-row
+                                +lbl('Confirm:')
+                                .col-xs-5.col-sm-4
+                                    input#profile_confirm.form-control(type='password' ng-model='user.confirm' ignite-match='user.password' placeholder='Confirm new password')
+                .col-xs-12.col-sm-12.details-row
+                    a.btn.btn-primary(ng-disabled='!profileCouldBeSaved()' ng-click='profileCouldBeSaved() && saveUser()' bs-tooltip='' data-title='{{saveBtnTipText()}}' data-placement='bottom' data-trigger='hover') Save

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/frontend/views/signin.jade
----------------------------------------------------------------------
diff --git a/modules/web-console/frontend/views/signin.jade b/modules/web-console/frontend/views/signin.jade
new file mode 100644
index 0000000..a6c64a8
--- /dev/null
+++ b/modules/web-console/frontend/views/signin.jade
@@ -0,0 +1,163 @@
+//-
+    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.
+
+mixin lblRequired(txt)
+    label.col-xs-3.col-md-3.required #{txt}
+
+header#header.header
+    table.container
+        tr
+            td.col-xs-3.col-sm-3.col-md-2
+                ignite-header-logo
+            td
+                ignite-header-title
+
+.container.body-container
+    .main-content(ng-controller='auth')
+        .row.home
+            .signin-greedy
+                .col-xs-12.col-md-6
+                    form(name='form' novalidate)
+                        .modal-body.row(style='padding: 0 0 10px 0; margin: 0')
+                            .settings-row(ng-if='action == "signup"')
+                                h3.login-header Sign Up
+                            .settings-row(ng-if='action == "signin"')
+                                h3.login-header Sign In
+                            .settings-row(ng-if='action == "password/forgot"')
+                                h3.login-header Forgot password?
+                            .settings-row
+                                p.col-xs-12.col-md-11(ng-show='action == "password/forgot"')
+                                    | That's ok! Simply enter your email below and a reset password link will be sent to you via email. You can then follow that link and select a new password.
+                            .settings-row(ng-show='action == "signin"')
+                                +lblRequired('Email:')
+                                .col-xs-9.col-md-8
+                                    input#signin_email.form-control(ignite-on-enter-focus-move='user_password' type='email' ng-model='ui.email' placeholder='Input email' required)
+                            .settings-row(ng-show='action == "signup"')
+                                +lblRequired('Email:')
+                                .col-xs-9.col-md-8
+                                    input#signup_email.form-control(ignite-on-enter-focus-move='user_password' type='email' ng-model='ui.email' placeholder='Input email' required)
+                            .settings-row(ng-show='action != "password/forgot"')
+                                +lblRequired('Password:')
+                                .col-xs-9.col-md-8
+                                    input#user_password.form-control(ignite-on-enter-focus-move='user_confirm' type='password' ng-model='ui.password' placeholder='Password' ng-required='action != "password/forgot"' ignite-on-enter='action == "signin" && form.$valid && auth(action, ui)')
+                            .settings-row(ng-if='action == "signup"')
+                                +lblRequired('Confirm:')
+                                .col-xs-9.col-md-8
+                                    input#user_confirm.form-control(ignite-on-enter-focus-move='first_name' type='password' ng-model='ui_exclude.confirm' ignite-match='ui.password' placeholder='Confirm password' ng-required='action == "signup"')
+                            .settings-row(ng-show='action == "signup"')
+                                +lblRequired('First Name:')
+                                .col-xs-9.col-md-8
+                                    input#first_name.form-control(ignite-on-enter-focus-move='last_name' type='text' ng-model='ui.firstName' placeholder='Input first name' ng-required='action=="signup"')
+                            .settings-row(ng-show='action == "signup"')
+                                +lblRequired('Last Name:')
+                                .col-xs-9.col-md-8
+                                    input#last_name.form-control(ignite-on-enter-focus-move='company' type='text' ng-model='ui.lastName' placeholder='Input last name' ng-required='action=="signup"')
+                            .settings-row(ng-show='action == "password/forgot"')
+                                +lblRequired('Email:')
+                                .col-xs-9.col-md-8
+                                    input#forgot_email.form-control(ignite-on-enter='form.$valid && forgotPassword(ui)' type='email' ng-model='ui.email' placeholder='Input email' required)
+                            .settings-row(ng-show='action == "signup"')
+                                +lblRequired('Company:')
+                                .col-xs-9.col-md-8
+                                    input#company.form-control(ignite-on-enter-focus-move='country' type='text' ng-model='ui.company' placeholder='Input company name' ng-required='action=="signup"')
+                            .settings-row(ng-show='action == "signup"')
+                                +lblRequired('Country:')
+                                .col-xs-9.col-md-8
+                                    button#country.select-toggle.form-control(ignite-on-enter-focus-move='signup' bs-select bs-options='item.name as item.name for item in countries' type='text' ng-model='ui.country' placeholder='Choose your country' ng-required='action=="signup"')
+                            .settings-row(ignite-terms)
+                                .col-md-offset-3(ng-if='action == "signup" && terms.termsState')
+                                    label
+                                        input(type='checkbox' ng-model='ui_exclude.agree', ng-required='true')
+                                        | I agree to the #[a(ui-sref='{{::terms.termsState}}' target='_blank') terms and conditions]
+                        .col-xs-12.col-md-11
+                            .login-footer(ng-show='action == "signup"')
+                                a.labelField(ng-click='action = "password/forgot"' ignite-on-click-focus='signin_email') Forgot password?
+                                a.labelLogin(ng-click='action = "signin"' ignite-on-click-focus='signin_email') Sign In
+                                button#signup.btn.btn-primary(ng-click='auth(action, ui)' ng-disabled='form.$invalid') Sign Up
+                        .col-xs-12.col-md-11
+                            .login-footer(ng-show='action == "password/forgot"')
+                                a.labelField(ng-click='action = "signin"' ignite-on-click-focus='signin_email') Sign In
+                                button#forgot.btn.btn-primary(ng-click='forgotPassword(ui)' ng-disabled='form.$invalid') Send it to me
+                        .col-xs-12.col-md-11
+                            .login-footer(ng-show='action == "signin"')
+                                a.labelField(ng-click='action = "password/forgot"' ignite-on-click-focus='signin_email') Forgot password?
+                                a.labelLogin(ng-click='action = "signup"' ignite-on-click-focus='first_name') Sign Up
+                                button#login.btn.btn-primary(ng-click='auth(action, ui)' ng-disabled='form.$invalid') Sign In
+
+                    .col-xs-12.col-md-11.home-panel
+                        ignite-features
+                .col-xs-12.col-md-6
+                    #carousel.carousel.slide
+                        // Indicators
+                        ol.carousel-indicators
+                            li.active(data-target='#carousel', data-slide-to='0')
+                            li(data-target='#carousel', data-slide-to='1')
+                            li(data-target='#carousel', data-slide-to='2')
+                            li(data-target='#carousel', data-slide-to='3')
+                            li(data-target='#carousel', data-slide-to='4')
+                            li(data-target='#carousel', data-slide-to='5')
+                            li(data-target='#carousel', data-slide-to='6')
+                        // Wrapper for slides
+                        .carousel-inner(role='listbox')
+                            .item.active
+                                img(src='/images/cluster.png', alt='Clusters screen')
+                                .carousel-caption
+                                    h3 Clusters screen
+                                    p Configure clusters, link clusters to caches
+                            .item
+                                img(src='/images/cache.png', alt='Caches screen')
+                                .carousel-caption
+                                    h3 Caches screen
+                                    p Configure caches, link domain models to caches, link caches to clusters
+                            .item
+                                img(src='/images/domains.png', alt='Domain model screen')
+                                .carousel-caption
+                                    h3 Domain model screen
+                                    p Manually enter domain model or import from database
+                            .item
+                                img(src='/images/summary.png', alt='Summary screen')
+                                .carousel-caption
+                                    h3 Summary screen
+                                    p Preview XML config, JAVA code,Docker file and download project
+                            .item
+                                img(src='/images/query-table.png', alt='Query')
+                                .carousel-caption
+                                    h3 Query
+                                    p Explain SQL, execute, scan queries
+                            .item
+                                img(src='/images/query-metadata.png', alt='Cache metadata')
+                                .carousel-caption
+                                    h3 Cache metadata
+                                    p View cache type metadata
+                            .item
+                                img(src='/images/query-chart.png', alt='Query chart')
+                                .carousel-caption
+                                    h3 Query chart
+                                    p View data in tabular form and as charts
+                        // Controls
+                        a.left.carousel-control(href='#carousel', ng-click='$event.preventDefault()', role='button', data-slide='prev')
+                            span.fa.fa-chevron-left(aria-hidden='true')
+                            span.sr-only Previous
+                        a.right.carousel-control(href='#carousel', ng-click='$event.preventDefault()', role='button', data-slide='next')
+                            span.fa.fa-chevron-right(aria-hidden='true')
+                            span.sr-only Next
+
+include includes/footer
+
+script.
+    $('.carousel').carousel()
+
+

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/frontend/views/sql/cache-metadata.jade
----------------------------------------------------------------------
diff --git a/modules/web-console/frontend/views/sql/cache-metadata.jade b/modules/web-console/frontend/views/sql/cache-metadata.jade
new file mode 100644
index 0000000..450c178
--- /dev/null
+++ b/modules/web-console/frontend/views/sql/cache-metadata.jade
@@ -0,0 +1,40 @@
+//-
+    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.
+.popover.cache-metadata(tabindex='-1' ignite-loading='loadingCacheMetadata' ignite-loading-text='Loading metadata...' ng-init='importMetadata()')
+    h3.popover-title
+        label.labelField Metadata for caches:
+        button.close(id='cache-metadata-close' ng-click='$hide()') &times;
+        .input-tip
+            input.form-control(type='text' ng-model='metaFilter' placeholder='Filter metadata...')
+    .popover-content(ng-if='metadata && metadata.length > 0')
+        treecontrol.tree-classic(tree-model='metadata' options='metaOptions' filter-expression='metaFilter')
+            span(ng-switch='' on='node.type')
+                span(ng-switch-when='type' ng-dblclick='dblclickMetadata(paragraph, node)')
+                    i.fa.fa-table
+                    label.clickable(ng-bind='node.displayName')
+                span(ng-switch-when='plain')
+                    label {{node.name}}
+                span(ng-switch-when='field' ng-dblclick='dblclickMetadata(paragraph, node)')
+                    i.fa(ng-class='node.system ? "fa-file-text-o" : "fa-file-o"')
+                    label.clickable {{node.name}} [{{node.clazz}}]
+                label(ng-switch-when='indexes') {{node.name}}
+                label(ng-switch-when='index') {{node.name}}
+                span(ng-switch-when='index-field' ng-dblclick='dblclickMetadata(paragraph, node)')
+                    i.fa(ng-class='node.order ? "fa-sort-amount-desc" : "fa-sort-amount-asc"')
+                    label.clickable {{node.name}}
+    .popover-content(ng-if='!metadata || metadata.length == 0')
+        label.content-empty No types found
+    h3.popover-footer Double click to paste into editor

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/frontend/views/sql/chart-settings.jade
----------------------------------------------------------------------
diff --git a/modules/web-console/frontend/views/sql/chart-settings.jade b/modules/web-console/frontend/views/sql/chart-settings.jade
new file mode 100644
index 0000000..5a1ceed
--- /dev/null
+++ b/modules/web-console/frontend/views/sql/chart-settings.jade
@@ -0,0 +1,40 @@
+//-
+    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.
+
+.popover.settings(tabindex='-1' style='width: 300px')
+    .arrow
+    h3.popover-title(style='color: black') Chart settings
+    button.close(id='chart-settings-close' ng-click='$hide()') &times;
+    .popover-content
+        form.form-horizontal.chart-settings(name='chartSettingsForm' novalidate)
+            .form-group.chart-settings
+                -var btnClass = 'col.value < 0 ? "btn-success" : "btn-default"'
+
+                label All columns (drag columns to axis)
+                ul.chart-settings-columns-list(dnd-list='paragraph.chartColumns' dnd-allowed-types='[]')
+                    li(ng-repeat='col in paragraph.chartColumns track by $index')
+                        .btn.btn-default.btn-chart-column-movable(ng-class=btnClass dnd-draggable='col' dnd-effect-allowed='copy') {{col.label}}
+                label X axis (accept only one column)
+                ul.chart-settings-columns-list(dnd-list='paragraph.chartKeyCols' dnd-drop='chartAcceptKeyColumn(paragraph, item)')
+                    li(ng-repeat='col in paragraph.chartKeyCols track by $index')
+                        .btn.btn-default.btn-chart-column(ng-class=btnClass) {{col.label}}
+                            i.fa.fa-close(ng-click='chartRemoveKeyColumn(paragraph, $index)')
+                label Y axis (accept only numeric columns)
+                ul.chart-settings-columns-list(dnd-list='paragraph.chartValCols' dnd-drop='chartAcceptValColumn(paragraph, item)')
+                    li(ng-repeat='col in paragraph.chartValCols track by $index')
+                        .btn.btn-default.btn-chart-column(ng-style='chartColor($index)') {{col.label}}
+                            button.btn-chart-column-agg-fx.select-toggle(ng-change='applyChartSettings(paragraph)' ng-show='paragraphTimeSpanVisible(paragraph)' ng-style='chartColor($index)' ng-model='col.aggFx' placeholder='...' bs-select bs-options='item for item in aggregateFxs' data-container='false' tabindex='-1')
+                            i.fa.fa-close(ng-click='chartRemoveValColumn(paragraph, $index)')

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/frontend/views/sql/notebook-new.jade
----------------------------------------------------------------------
diff --git a/modules/web-console/frontend/views/sql/notebook-new.jade b/modules/web-console/frontend/views/sql/notebook-new.jade
new file mode 100644
index 0000000..09b2dae
--- /dev/null
+++ b/modules/web-console/frontend/views/sql/notebook-new.jade
@@ -0,0 +1,31 @@
+//-
+    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.
+
+.modal(tabindex='-1' role='dialog')
+    .modal-dialog
+        .modal-content
+            .modal-header
+                button.close(ng-click='$hide()') &times;
+                h4.modal-title New SQL notebook
+            form.form-horizontal.modal-body.row(name='ui.inputForm' novalidate)
+                div
+                    .col-sm-2
+                        label.required.labelFormField Name:&nbsp;
+                    .col-sm-10
+                        input.form-control(id='create-notebook' type='text' ng-model='name' required ignite-on-enter='ui.inputForm.$valid && create(name)' ignite-auto-focus)
+            .modal-footer
+                button.btn.btn-default(id='copy-btn-cancel' ng-click='$hide()') Cancel
+                button.btn.btn-primary(id='copy-btn-confirm' ng-disabled='ui.inputForm.$invalid' ng-click='create(name)') Create

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/frontend/views/sql/paragraph-rate.jade
----------------------------------------------------------------------
diff --git a/modules/web-console/frontend/views/sql/paragraph-rate.jade b/modules/web-console/frontend/views/sql/paragraph-rate.jade
new file mode 100644
index 0000000..03c6497
--- /dev/null
+++ b/modules/web-console/frontend/views/sql/paragraph-rate.jade
@@ -0,0 +1,31 @@
+//-
+    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.
+
+.popover.settings(tabindex='-1' style='width: 200px')
+    .arrow
+    h3.popover-title(style='color: black') Refresh rate
+    button.close(id='paragraph-rate-close' ng-click='$hide()') &times;
+    .popover-content
+        form(name='popoverForm' novalidate)
+            .form-group(style='padding: 5px')
+                .col-sm-4
+                    input.form-control(id='paragraph-rate' ng-init='value = paragraph.rate.value' ng-model='value' type='number' min='1' required ignite-auto-focus)
+                .col-sm-8(style='padding-left: 5px')
+                    button.form-control.select-toggle(id='paragraph-unit' ng-init='unit = paragraph.rate.unit' ng-model='unit' required placeholder='Time unit' bs-select bs-options='item.value as item.label for item in timeUnit' data-container='false' tabindex='0')
+            .form-actions(style='margin-top: 30px; padding: 5px')
+                button.btn.btn-primary(id='paragraph-rate-start' ng-disabled='popoverForm.$invalid' ng-click='startRefresh(paragraph, value, unit); $hide()') Start
+                button.btn.btn-primary.btn-default(id='paragraph-rate-stop' ng-click='stopRefresh(paragraph); $hide()' ng-disabled='!paragraph.rate.installed') Stop
+

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/frontend/views/sql/sql.jade
----------------------------------------------------------------------
diff --git a/modules/web-console/frontend/views/sql/sql.jade b/modules/web-console/frontend/views/sql/sql.jade
new file mode 100644
index 0000000..81acdfd
--- /dev/null
+++ b/modules/web-console/frontend/views/sql/sql.jade
@@ -0,0 +1,193 @@
+//-
+    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.
+
+mixin btn-toolbar(btn, click, tip, focusId)
+    i.btn.btn-default.fa(class=btn ng-click=click bs-tooltip='' data-title=tip ignite-on-click-focus=focusId data-trigger='hover' data-placement='bottom')
+
+mixin btn-toolbar-data(btn, kind, tip)
+    i.btn.btn-default.fa(class=btn ng-click='setResult(paragraph, "#{kind}")' ng-class='{active: resultEq(paragraph, "#{kind}")}' bs-tooltip='' data-title=tip data-trigger='hover' data-placement='bottom')
+
+mixin result-toolbar
+    .btn-group(ng-model='paragraph.result' ng-click='$event.stopPropagation()' style='left: 50%; margin: 0 0 0 -70px;display: block;')
+        +btn-toolbar-data('fa-table', 'table', 'Show data in tabular form')
+        +btn-toolbar-data('fa-bar-chart', 'bar', 'Show bar chart<br/>By default first column - X values, second column - Y values<br/>In case of one column it will be treated as Y values')
+        +btn-toolbar-data('fa-pie-chart', 'pie', 'Show pie chart<br/>By default first column - pie labels, second column - pie values<br/>In case of one column it will be treated as pie values')
+        +btn-toolbar-data('fa-line-chart', 'line', 'Show line chart<br/>By default first column - X values, second column - Y values<br/>In case of one column it will be treated as Y values')
+        +btn-toolbar-data('fa-area-chart', 'area', 'Show area chart<br/>By default first column - X values, second column - Y values<br/>In case of one column it will be treated as Y values')
+
+mixin chart-settings
+    .total.row
+        .col-xs-4
+            .chart-settings-link(ng-show='paragraph.chart && paragraph.chartColumns.length > 0')
+                a(title='Click to show chart settings dialog' ng-click='$event.stopPropagation()' bs-popover data-template-url='/sql/chart-settings.html' data-placement='bottom' data-auto-close='1' data-trigger='click')
+                    i.fa.fa-bars
+                    | Chart settings
+                div(ng-show='paragraphTimeSpanVisible(paragraph)')
+                    label Show
+                    button.select-manual-caret.btn.btn-default(ng-model='paragraph.timeLineSpan' ng-change='applyChartSettings(paragraph)' bs-options='item for item in timeLineSpans' bs-select data-caret-html='<span class="caret"></span>')
+                    label min
+        .col-xs-4
+            +result-toolbar
+
+mixin notebook-rename
+    .docs-header.notebook-header
+        h1.col-sm-6(ng-hide='notebook.edit')
+            label(style='max-width: calc(100% - 60px)') {{notebook.name}}
+            .btn-group(ng-if='!demo')
+                +btn-toolbar('fa-pencil', 'notebook.edit = true;notebook.editName = notebook.name', 'Rename notebook')
+                +btn-toolbar('fa-trash', 'removeNotebook(notebook)', 'Remove notebook')
+        h1.col-sm-6(ng-show='notebook.edit')
+            i.btn.fa.fa-floppy-o(ng-show='notebook.editName' ng-click='renameNotebook(notebook.editName)' bs-tooltip data-title='Save notebook name' data-trigger='hover')
+            .input-tip
+                input.form-control(ng-model='notebook.editName' required ignite-on-enter='renameNotebook(notebook.editName)' ignite-on-escape='notebook.edit = false;')
+        h1.pull-right
+            a.dropdown-toggle(data-toggle='dropdown' bs-dropdown='scrollParagraphs' data-placement='bottom-right') Scroll to query
+                span.caret
+            .btn-group(style='margin-top: 2px')
+                +btn-toolbar('fa-plus', 'addParagraph()', 'Add new query')
+
+mixin notebook-error
+    h2 Failed to load notebook
+    label.col-sm-12 Notebook not accessible any more. Go back to configuration or open to another notebook.
+    button.h3.btn.btn-primary(ui-sref='base.configuration.clusters') Back to configuration
+
+mixin paragraph-rename
+    .col-sm-6(ng-hide='paragraph.edit')
+        i.tipLabel.fa(ng-class='paragraphExpanded(paragraph) ? "fa-chevron-circle-down" : "fa-chevron-circle-right"')
+        label {{paragraph.name}}
+
+        .btn-group(ng-hide='notebook.paragraphs.length > 1')
+            +btn-toolbar('fa-pencil', 'paragraph.edit = true; paragraph.editName = paragraph.name; $event.stopPropagation();', 'Rename query', 'paragraph-name-{{paragraph.id}}')
+
+        .btn-group(ng-show='notebook.paragraphs.length > 1' ng-click='$event.stopPropagation();')
+            +btn-toolbar('fa-pencil', 'paragraph.edit = true; paragraph.editName = paragraph.name;', 'Rename query', 'paragraph-name-{{paragraph.id}}')
+            +btn-toolbar('fa-remove', 'removeParagraph(paragraph)', 'Remove query')
+
+    .col-sm-6(ng-show='paragraph.edit')
+        i.tipLabel.fa(style='float: left;' ng-class='paragraphExpanded(paragraph) ? "fa-chevron-circle-down" : "fa-chevron-circle-right"')
+        i.tipLabel.fa.fa-floppy-o(style='float: right;' ng-show='paragraph.editName' ng-click='renameParagraph(paragraph, paragraph.editName); $event.stopPropagation();' bs-tooltip data-title='Save query name' data-trigger='hover')
+        .input-tip
+            input.form-control(id='paragraph-name-{{paragraph.id}}' ng-model='paragraph.editName' required ng-click='$event.stopPropagation();' ignite-on-enter='renameParagraph(paragraph, paragraph.editName)' ignite-on-escape='paragraph.edit = false')
+
+mixin query-controls
+    .sql-controls
+        a.btn.btn-primary(ng-disabled='!actionAvailable(paragraph, true)' ng-click='execute(paragraph)' data-placement='bottom' bs-tooltip='' data-title='{{actionTooltip(paragraph, "execute", true)}}') Execute
+        a.btn.btn-primary(ng-disabled='!actionAvailable(paragraph, true)' ng-click='explain(paragraph)' data-placement='bottom' bs-tooltip='' data-title='{{actionTooltip(paragraph, "explain", true)}}') Explain
+        .btn-group(bs-tooltip='' data-title='{{actionTooltip(paragraph, "execute scan", false)}}' data-placement='bottom')
+            a.btn.btn-primary.fieldButton(ng-disabled='!actionAvailable(paragraph, false)' ng-click='scan(paragraph)') Scan
+            a.btn.btn-primary(ng-disabled='!actionAvailable(paragraph, false)' data-toggle='dropdown' data-container='body' bs-dropdown='[{ text: "Scan with filter", click: "actionAvailable(paragraph, false) && scanWithFilter(paragraph)" }]')
+                span.caret
+
+        .pull-right
+            label.tipLabel System columns:
+            a.btn.btn-default.fa.fa-bars.tipLabel(ng-class='{"btn-info": paragraph.systemColumns}' ng-click='toggleSystemColumns(paragraph)' ng-disabled='paragraph.disabledSystemColumns' bs-tooltip data-title='Show "_KEY", "_VAL" columns')
+            label.tipLabel Refresh rate:
+            button.btn.btn-default.fa.fa-clock-o.tipLabel(title='Click to show refresh rate dialog' ng-class='{"btn-info": paragraph.rate && paragraph.rate.installed}' bs-popover data-template-url='/sql/paragraph-rate.html' data-placement='left' data-auto-close='1' data-trigger='click') {{rateAsString(paragraph)}}
+            label.tipLabel Page size:
+            button.select-toggle.fieldButton.btn.btn-default(ng-model='paragraph.pageSize' bs-options='item for item in pageSizes' bs-select bs-tooltip data-placement='bottom-right' data-title='Max number of rows to show in query result as one page')
+
+mixin table-result
+    .total.row
+        .col-xs-4
+            label Page: #[b {{paragraph.page}}]
+            label.margin-left-dflt Results so far: #[b {{paragraph.rows.length + paragraph.total}}]
+            label.margin-left-dflt Duration: #[b {{paragraph.duration | duration}}]
+        .col-xs-4
+            +result-toolbar
+        .col-xs-4
+            .btn-group.pull-right(ng-disabled='paragraph.loading')
+                button.btn.btn-primary.fieldButton(ng-click='exportCsv(paragraph)' bs-tooltip data-title='{{actionTooltip(paragraph, "export", false)}}') Export
+                button.btn.btn-primary(id='export-item-dropdown' data-toggle='dropdown' data-container='body' bs-dropdown='exportDropdown' data-placement='bottom-right')
+                    span.caret
+    .grid(ui-grid='paragraph.gridOptions' ui-grid-resize-columns ui-grid-exporter)
+
+mixin chart-result
+    div(ng-hide='paragraph.scanExplain()')
+        +chart-settings
+        .empty(ng-show='paragraph.chartColumns.length > 0 && !paragraph.chartColumnsConfigured()') Cannot display chart. Please configure axis using #[b Chart settings]
+        .empty(ng-show='paragraph.chartColumns.length == 0') Cannot display chart. Result set must contain Java build-in type columns. Please change query and execute it again.
+        div(ng-show='paragraph.chartColumnsConfigured()')
+            div(ng-show='paragraph.timeLineSupported() || !paragraph.chartTimeLineEnabled()')
+                div(ng-repeat='chart in paragraph.charts')
+                    nvd3(options='chart.options' data='chart.data' api='chart.api')
+            .empty(ng-show='!paragraph.timeLineSupported() && paragraph.chartTimeLineEnabled()') Pie chart does not support 'TIME_LINE' column for X-axis. Please use another column for X-axis or switch to another chart.
+    .empty(ng-show='paragraph.scanExplain()')
+        .row
+            .col-xs-4.col-xs-offset-4
+                +result-toolbar
+        label.margin-top-dflt Charts do not support #[b Explain] and #[b Scan] query
+
+.row(ng-controller='sqlController')
+    .docs-content
+        .row(ng-if='notebook' bs-affix style='margin-bottom: 20px;')
+            +notebook-rename
+
+        ignite-information(data-title='With SQL notebook you can' style='margin-top: 0; margin-bottom: 30px')
+            ul
+                li Create any number of queries
+                li Execute and explain SQL queries
+                li Execute scan queries
+                li View data in tabular form and as charts
+
+        div(ng-if='notebookLoadFailed' style='text-align: center')
+            +notebook-error
+
+        div(ng-if='notebook' ignite-loading='sqlLoading' ignite-loading-text='{{ loadingText }}' ignite-loading-position='top')
+            .docs-body.paragraphs
+                .panel-group(bs-collapse ng-model='notebook.expandedParagraphs' data-allow-multiple='true' data-start-collapsed='false')
+                    .panel.panel-default(ng-repeat='paragraph in notebook.paragraphs' id='{{paragraph.id}}')
+                        .panel-heading(bs-collapse-toggle)
+                            .row
+                                +paragraph-rename
+                        .panel-collapse(role='tabpanel' bs-collapse-target)
+                            .col-sm-12
+                                .col-xs-8.col-sm-9(style='border-right: 1px solid #eee')
+                                    .sql-editor(ignite-ace='{onLoad: aceInit(paragraph), theme: "chrome", mode: "sql", require: ["ace/ext/language_tools"],' +
+                                    'advanced: {enableSnippets: false, enableBasicAutocompletion: true, enableLiveAutocompletion: true}}'
+                                    ng-model='paragraph.query')
+                                .col-xs-4.col-sm-3
+                                    div(ng-show='caches.length > 0' style='padding: 5px 10px' st-table='displayedCaches' st-safe-src='caches')
+                                        lable.labelField.labelFormField Caches:
+                                        i.fa.fa-database.tipField(title='Click to show cache types metadata dialog' bs-popover data-template-url='/sql/cache-metadata.html' data-placement='bottom' data-trigger='click' data-container='#{{ paragraph.id}}')
+                                        .input-tip
+                                            input.form-control(type='text' st-search='label' placeholder='Filter caches...')
+                                        table.links
+                                            tbody.scrollable-y(style='max-height: 15em; display: block;')
+                                                tr(ng-repeat='cache in displayedCaches track by cache.name')
+                                                    td(style='width: 100%')
+                                                        input.labelField(id='cache{{$index}}' type='radio' value='{{cache.name}}' ng-model='paragraph.cacheName')
+                                                        label(for='cache{{$index}}' ng-bind='cache.label')
+                                    .empty-caches(ng-show='displayedCaches.length == 0 && caches.length != 0')
+                                        label Wrong caches filter
+                                    .empty-caches(ng-show='caches.length == 0')
+                                        label No caches
+                            .col-sm-12
+                                +query-controls
+                            .col-sm-12.sql-result(ng-if='paragraph.queryExecuted()' ng-switch='paragraph.resultType()')
+                                .error(ng-switch-when='error') Error: {{paragraph.errMsg}}
+                                .empty(ng-switch-when='empty') Result set is empty
+                                .table(ng-switch-when='table')
+                                    +table-result
+                                .chart(ng-switch-when='chart')
+                                    +chart-result
+                                .footer.clearfix(ng-show='paragraph.nonRefresh()')
+                                    a.pull-left(ng-click='showResultQuery(paragraph)') Show query
+
+                                    -var nextVisibleCondition = 'paragraph.queryId && (paragraph.table() || paragraph.chart() && (paragraph.timeLineSupported() || !paragraph.chartTimeLineEnabled()))'
+
+                                    .pull-right(ng-show=nextVisibleCondition ng-class='{disabled: paragraph.loading}' ng-click='!paragraph.loading && nextPage(paragraph)')
+                                        i.fa.fa-chevron-circle-right
+                                        a Next

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/frontend/views/templates/agent-download.jade
----------------------------------------------------------------------
diff --git a/modules/web-console/frontend/views/templates/agent-download.jade b/modules/web-console/frontend/views/templates/agent-download.jade
new file mode 100644
index 0000000..864694b
--- /dev/null
+++ b/modules/web-console/frontend/views/templates/agent-download.jade
@@ -0,0 +1,48 @@
+//-
+    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.
+
+.modal.center(tabindex='-1' role='dialog')
+    .modal-dialog
+        .modal-content
+            #errors-container.modal-header.header
+                h4.modal-title(ng-if='!hasAgents') Connection to Ignite Web Agent is not established
+                h4.modal-title(ng-if='hasAgents') Connection to Ignite Node is not established
+            .agent-download(ng-if='!hasAgents')
+                p Please download and run #[a(href='javascript:void(0)' ng-click='downloadAgent()') ignite-web-agent] in order to {{::agentGoal}}
+                p For run:
+                ul
+                    li Download and unzip #[a(href='javascript:void(0)' ng-click='downloadAgent()') ignite-web-agent] archive
+                    li Run shell file #[b ignite-web-agent.{sh|bat}]
+                p Refer to #[b README.txt] in agent folder for more information
+                .modal-advanced-options
+                    i.fa.fa-chevron-circle-down(ng-show='agentLoad.showToken' ng-click='agentLoad.showToken = ! agentLoad.showToken')
+                    i.fa.fa-chevron-circle-right(ng-show='!agentLoad.showToken' ng-click='agentLoad.showToken = ! agentLoad.showToken')
+                    a(ng-click='agentLoad.showToken = ! agentLoad.showToken') {{agentLoad.showToken ? 'Hide security token...' : 'Show security token...'}}
+                .details-row(ng-show='agentLoad.showToken')
+                    label.labelField Security token: {{user.token}}
+                    i.tipLabel.fa.fa-clipboard(ignite-copy-to-clipboard='{{user.token}}' bs-tooltip='' data-title='Copy security token to clipboard')
+                    i.tipLabel.fa.fa-question-circle(ng-if=lines bs-tooltip='' data-title='The security token is used for authorization of web agent')
+            .agent-download(ng-if='hasAgents')
+                p Connection to Ignite Web Agent is established, but agent failed to connect to Ignite Node
+                p Please check the following:
+                ul
+                    li Ignite Grid is up and running
+                    li In agent settings check URI for connect to Ignite REST server
+                    li Check agent logs for errors
+                    li Refer to #[b README.txt] in agent folder for more information
+            .modal-footer
+                button.btn.btn-default(ng-click='back()') {{::backText}}
+                button.btn.btn-primary(ng-if='!hasAgents' ng-click='downloadAgent()') Download agent

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/frontend/views/templates/alert.jade
----------------------------------------------------------------------
diff --git a/modules/web-console/frontend/views/templates/alert.jade b/modules/web-console/frontend/views/templates/alert.jade
new file mode 100644
index 0000000..182ba99
--- /dev/null
+++ b/modules/web-console/frontend/views/templates/alert.jade
@@ -0,0 +1,21 @@
+//-
+    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.
+
+.alert(ng-show='type' ng-class='[type ? "alert-" + type : null]')
+    button.close(type='button', ng-if='dismissable', ng-click='$hide()') &times;
+    i.alert-icon.fa(ng-if='icon' ng-class='[icon]')
+    span.alert-title(ng-bind-html='title')
+    span.alert-content(ng-bind-html='content')


[37/52] ignite git commit: Web Console beta-3.

Posted by ak...@apache.org.
http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/frontend/app/modules/loading/loading.css
----------------------------------------------------------------------
diff --git a/modules/web-console/frontend/app/modules/loading/loading.css b/modules/web-console/frontend/app/modules/loading/loading.css
new file mode 100644
index 0000000..87bbc6a
--- /dev/null
+++ b/modules/web-console/frontend/app/modules/loading/loading.css
@@ -0,0 +1,73 @@
+/*
+ * 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-loading] {
+    position: relative;
+}
+
+.loading {
+    position: absolute;
+    bottom: 0;
+    left: 0;
+    right: 0;
+    top: 0;
+    z-index: 1001;
+    opacity: 0;
+    visibility: hidden;
+    background-color: white;
+    transition: visibility 0s 0.5s, opacity 0.5s linear;
+}
+
+.loading-active {
+    opacity: 1;
+    visibility: visible;
+    transition: opacity 0.5s linear;
+}
+
+.loading:before {
+    content: '';
+    display: inline-block;
+    height: 100%;
+    vertical-align: middle;
+}
+
+.loading .loading-wrapper {
+    display: inline-block;
+    vertical-align: middle;
+    position: relative;
+    width: 100%;
+}
+
+.loading.loading-top .loading-wrapper {
+    position: absolute;
+    top: 100px;
+    display: block;
+}
+
+.loading .loading-text {
+    font-size: 18px;
+    margin: 20px 0;
+    text-align: center;
+}
+
+.loading-opacity-80 {
+    opacity: 0.8;
+}
+
+.loading-max-foreground {
+    z-index: 99999;
+}

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/frontend/app/modules/loading/loading.directive.js
----------------------------------------------------------------------
diff --git a/modules/web-console/frontend/app/modules/loading/loading.directive.js b/modules/web-console/frontend/app/modules/loading/loading.directive.js
new file mode 100644
index 0000000..064b4c2
--- /dev/null
+++ b/modules/web-console/frontend/app/modules/loading/loading.directive.js
@@ -0,0 +1,51 @@
+/*
+ * 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 templateUrl from './loading.jade';
+import './loading.css';
+
+export default ['igniteLoading', ['IgniteLoading', '$templateCache', '$compile', (Loading, $templateCache, $compile) => {
+    const link = (scope, element) => {
+        const compiledTemplate = $compile($templateCache.get(templateUrl));
+
+        const build = () => {
+            scope.position = scope.position || 'middle';
+
+            const loading = compiledTemplate(scope);
+
+            if (!scope.loading) {
+                scope.loading = loading;
+
+                Loading.add(scope.key || 'defaultSpinnerKey', scope.loading);
+                element.append(scope.loading);
+            }
+        };
+
+        build();
+    };
+
+    return {
+        scope: {
+            key: '@igniteLoading',
+            text: '@?igniteLoadingText',
+            class: '@?igniteLoadingClass',
+            position: '@?igniteLoadingPosition'
+        },
+        restrict: 'A',
+        link
+    };
+}]];

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/frontend/app/modules/loading/loading.jade
----------------------------------------------------------------------
diff --git a/modules/web-console/frontend/app/modules/loading/loading.jade b/modules/web-console/frontend/app/modules/loading/loading.jade
new file mode 100644
index 0000000..cc6cf45
--- /dev/null
+++ b/modules/web-console/frontend/app/modules/loading/loading.jade
@@ -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.
+
+.loading.loading-opacity-80(ng-class='[class, "loading-" + position]')
+    .loading-wrapper
+        .spinner
+            .bounce1
+            .bounce2
+            .bounce3
+        .loading-text {{ text }}

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/frontend/app/modules/loading/loading.module.js
----------------------------------------------------------------------
diff --git a/modules/web-console/frontend/app/modules/loading/loading.module.js b/modules/web-console/frontend/app/modules/loading/loading.module.js
new file mode 100644
index 0000000..889cd6b
--- /dev/null
+++ b/modules/web-console/frontend/app/modules/loading/loading.module.js
@@ -0,0 +1,26 @@
+/*
+ * 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 IgniteLoadingDirective from './loading.directive';
+import IgniteLoadingService from './loading.service';
+
+angular
+    .module('ignite-console.loading', [])
+    .directive(...IgniteLoadingDirective)
+    .service(...IgniteLoadingService);

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/frontend/app/modules/loading/loading.service.js
----------------------------------------------------------------------
diff --git a/modules/web-console/frontend/app/modules/loading/loading.service.js b/modules/web-console/frontend/app/modules/loading/loading.service.js
new file mode 100644
index 0000000..ec31c1a
--- /dev/null
+++ b/modules/web-console/frontend/app/modules/loading/loading.service.js
@@ -0,0 +1,48 @@
+/*
+ * 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 ['IgniteLoading', ['$timeout', ($timeout) => {
+    const _overlays = {};
+
+    const start = (key) => {
+        $timeout(() => {
+            const loadingOverlay = _overlays[key];
+
+            loadingOverlay && loadingOverlay.addClass('loading-active');
+        });
+    };
+
+    const finish = (key) => {
+        $timeout(() => {
+            const loadingOverlay = _overlays[key];
+
+            loadingOverlay && loadingOverlay.removeClass('loading-active');
+        });
+    };
+
+    const add = (key, element) => {
+        _overlays[key] = element;
+
+        return element;
+    };
+
+    return {
+        add,
+        start,
+        finish
+    };
+}]];

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/frontend/app/modules/navbar/Navbar.provider.js
----------------------------------------------------------------------
diff --git a/modules/web-console/frontend/app/modules/navbar/Navbar.provider.js b/modules/web-console/frontend/app/modules/navbar/Navbar.provider.js
new file mode 100644
index 0000000..f1ae1b2
--- /dev/null
+++ b/modules/web-console/frontend/app/modules/navbar/Navbar.provider.js
@@ -0,0 +1,28 @@
+/*
+ * 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 ['IgniteNavbar', [function() {
+    const items = [];
+
+    this.push = function(data) {
+        items.push(data);
+    };
+
+    this.$get = [function() {
+        return items;
+    }];
+}]];

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/frontend/app/modules/navbar/Userbar.provider.js
----------------------------------------------------------------------
diff --git a/modules/web-console/frontend/app/modules/navbar/Userbar.provider.js b/modules/web-console/frontend/app/modules/navbar/Userbar.provider.js
new file mode 100644
index 0000000..9513641
--- /dev/null
+++ b/modules/web-console/frontend/app/modules/navbar/Userbar.provider.js
@@ -0,0 +1,28 @@
+/*
+ * 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 ['IgniteUserbar', [function() {
+    const items = [];
+
+    this.push = function(data) {
+        items.push(data);
+    };
+
+    this.$get = [function() {
+        return items;
+    }];
+}]];

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/frontend/app/modules/navbar/navbar.directive.js
----------------------------------------------------------------------
diff --git a/modules/web-console/frontend/app/modules/navbar/navbar.directive.js b/modules/web-console/frontend/app/modules/navbar/navbar.directive.js
new file mode 100644
index 0000000..020cfe4
--- /dev/null
+++ b/modules/web-console/frontend/app/modules/navbar/navbar.directive.js
@@ -0,0 +1,30 @@
+/*
+ * 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 ['igniteNavbar', ['IgniteNavbar', (IgniteNavbar) => {
+    function controller() {
+        const ctrl = this;
+
+        ctrl.items = IgniteNavbar;
+    }
+
+    return {
+        restrict: 'A',
+        controller,
+        controllerAs: 'navbar'
+    };
+}]];

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/frontend/app/modules/navbar/navbar.module.js
----------------------------------------------------------------------
diff --git a/modules/web-console/frontend/app/modules/navbar/navbar.module.js b/modules/web-console/frontend/app/modules/navbar/navbar.module.js
new file mode 100644
index 0000000..b845cbc
--- /dev/null
+++ b/modules/web-console/frontend/app/modules/navbar/navbar.module.js
@@ -0,0 +1,33 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import angular from 'angular';
+
+import IgniteNavbar from './Navbar.provider';
+import IgniteUserbar from './Userbar.provider';
+
+import igniteNavbar from './navbar.directive';
+import igniteUserbar from './userbar.directive';
+
+angular
+.module('ignite-console.navbar', [
+
+])
+.provider(...IgniteNavbar)
+.provider(...IgniteUserbar)
+.directive(...igniteNavbar)
+.directive(...igniteUserbar);

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/frontend/app/modules/navbar/userbar.directive.js
----------------------------------------------------------------------
diff --git a/modules/web-console/frontend/app/modules/navbar/userbar.directive.js b/modules/web-console/frontend/app/modules/navbar/userbar.directive.js
new file mode 100644
index 0000000..af70eb1
--- /dev/null
+++ b/modules/web-console/frontend/app/modules/navbar/userbar.directive.js
@@ -0,0 +1,48 @@
+/*
+ * 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 ['igniteUserbar', [function() {
+    return {
+        restrict: 'A',
+        controller: ['$rootScope', 'IgniteUserbar', 'AclService', function($root, IgniteUserbar, AclService) {
+            const ctrl = this;
+
+            ctrl.items = [
+                {text: 'Profile', sref: 'settings.profile'},
+                {text: 'Getting started', click: 'gettingStarted.tryShow(true)'}
+            ];
+
+            const _rebuildSettings = () => {
+                ctrl.items.splice(2);
+
+                if (AclService.can('admin_page'))
+                    ctrl.items.push({text: 'Admin panel', sref: 'settings.admin'});
+
+                ctrl.items.push(...IgniteUserbar);
+
+                if (AclService.can('logout'))
+                    ctrl.items.push({text: 'Log out', sref: 'logout'});
+            };
+
+            if ($root.user)
+                _rebuildSettings(null, $root.user);
+
+            $root.$on('user', _rebuildSettings);
+        }],
+        controllerAs: 'userbar'
+    };
+}]];

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/frontend/app/modules/socket.module.js
----------------------------------------------------------------------
diff --git a/modules/web-console/frontend/app/modules/socket.module.js b/modules/web-console/frontend/app/modules/socket.module.js
new file mode 100644
index 0000000..17856c4
--- /dev/null
+++ b/modules/web-console/frontend/app/modules/socket.module.js
@@ -0,0 +1,41 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import angular from 'angular';
+import io from 'socket.io-client'; // eslint-disable-line no-unused-vars
+
+angular
+.module('ignite-console.socket', [
+])
+.provider('igniteSocketFactory', [function() {
+    let _options = {};
+
+    /**
+     * @param {Object} options Socket io options.
+     */
+    this.set = (options) => {
+        _options = options;
+    };
+
+    this.$get = ['socketFactory', function(socketFactory) {
+        return () => {
+            const ioSocket = io.connect(_options);
+
+            return socketFactory({ioSocket});
+        };
+    }];
+}]);

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/frontend/app/modules/sql/Notebook.data.js
----------------------------------------------------------------------
diff --git a/modules/web-console/frontend/app/modules/sql/Notebook.data.js b/modules/web-console/frontend/app/modules/sql/Notebook.data.js
new file mode 100644
index 0000000..aef72eb
--- /dev/null
+++ b/modules/web-console/frontend/app/modules/sql/Notebook.data.js
@@ -0,0 +1,157 @@
+/*
+ * 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: 50,
+            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: 50,
+            query: 'SELECT * FROM "CarCache".Car',
+            result: 'table',
+            timeLineSpan: '1',
+            rate: {
+                value: 30,
+                unit: 1000,
+                installed: false
+            }
+        },
+        {
+            name: 'Query with aggregates',
+            cacheName: 'CarCache',
+            pageSize: 50,
+            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;
+    }
+
+    read() {
+        if (!_.isNil(this.initLatch))
+            return this.initLatch;
+
+        if (this.demo)
+            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));
+    }
+
+    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/6af6560a/modules/web-console/frontend/app/modules/sql/Notebook.service.js
----------------------------------------------------------------------
diff --git a/modules/web-console/frontend/app/modules/sql/Notebook.service.js b/modules/web-console/frontend/app/modules/sql/Notebook.service.js
new file mode 100644
index 0000000..12730be
--- /dev/null
+++ b/modules/web-console/frontend/app/modules/sql/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.clusters');
+            });
+    }
+
+    remove(notebook) {
+        return this.confirmModal.confirm(`Are you sure you want to remove: "${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);
+            });
+    }
+}

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/frontend/app/modules/sql/notebook.controller.js
----------------------------------------------------------------------
diff --git a/modules/web-console/frontend/app/modules/sql/notebook.controller.js b/modules/web-console/frontend/app/modules/sql/notebook.controller.js
new file mode 100644
index 0000000..f10a4d0
--- /dev/null
+++ b/modules/web-console/frontend/app/modules/sql/notebook.controller.js
@@ -0,0 +1,60 @@
+/*
+ * 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.
+ */
+
+// Controller that load notebooks in navigation bar .
+export default ['$scope', '$modal', '$state', 'IgniteMessages', 'IgniteNotebook',
+    (scope, $modal, $state, Messages, Notebook) => {
+        // Pre-fetch modal dialogs.
+        const nameModal = $modal({scope, templateUrl: '/sql/notebook-new.html', show: false});
+
+        scope.create = (name) => {
+            return Notebook.create(name)
+                .then((notebook) => {
+                    nameModal.hide();
+
+                    $state.go('base.sql.notebook', {noteId: notebook._id});
+                })
+                .catch(Messages.showError);
+        };
+
+        scope.createNotebook = () => nameModal.$promise.then(nameModal.show);
+
+        Notebook.read()
+            .then((notebooks) => {
+                scope.$watchCollection(() => notebooks, (changed) => {
+                    if (!changed.length)
+                        return scope.notebooks = [];
+
+                    scope.notebooks = [
+                        {text: 'Create new notebook', click: scope.createNotebook},
+                        {divider: true}
+                    ];
+
+                    _.forEach(changed, (notebook) => scope.notebooks.push({
+                        data: notebook,
+                        action: {
+                            icon: 'fa-trash',
+                            click: (item) => Notebook.remove(item)
+                        },
+                        text: notebook.name,
+                        sref: `base.sql.notebook({noteId:"${notebook._id}"})`
+                    }));
+                });
+            })
+            .catch(Messages.showError);
+    }
+];

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/frontend/app/modules/sql/scan-filter-input.jade
----------------------------------------------------------------------
diff --git a/modules/web-console/frontend/app/modules/sql/scan-filter-input.jade b/modules/web-console/frontend/app/modules/sql/scan-filter-input.jade
new file mode 100644
index 0000000..addc5f3
--- /dev/null
+++ b/modules/web-console/frontend/app/modules/sql/scan-filter-input.jade
@@ -0,0 +1,39 @@
+//-
+    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 ../../helpers/jade/mixins.jade
+
+.modal(tabindex='-1' role='dialog')
+    .modal-dialog
+        .modal-content
+            .modal-header
+                button.close(ng-click='$hide()') &times;
+                h4.modal-title Scan filter
+            form.form-horizontal.modal-body.row(name='ui.inputForm' novalidate)
+                .settings-row
+                    .col-sm-2
+                        label.required.labelFormField Filter:&nbsp;
+                    .col-sm-10
+                        .input-tip
+                            +ignite-form-field-input('"filter"', 'ui.filter', false, 'true', 'Enter filter')(
+                                data-ignite-form-field-input-autofocus='true'
+                                ignite-on-enter='form.$valid && ok()'
+                            )
+                .settings-row
+                    +checkbox('Case sensitive search', 'ui.caseSensitive', '"caseSensitive"', 'Select this checkbox for case sensitive search')
+            .modal-footer
+                button.btn.btn-default(id='btn-cancel' ng-click='$hide()') Cancel
+                button.btn.btn-primary(id='btn-scan' ng-disabled='ui.inputForm.$invalid' ng-click='ok()') Scan

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/frontend/app/modules/sql/scan-filter-input.service.js
----------------------------------------------------------------------
diff --git a/modules/web-console/frontend/app/modules/sql/scan-filter-input.service.js b/modules/web-console/frontend/app/modules/sql/scan-filter-input.service.js
new file mode 100644
index 0000000..18ba3ba
--- /dev/null
+++ b/modules/web-console/frontend/app/modules/sql/scan-filter-input.service.js
@@ -0,0 +1,51 @@
+/*
+ * 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 ScanFilter {
+    static $inject = ['$rootScope', '$q', '$modal'];
+
+    constructor($root, $q, $modal) {
+        this.deferred = null;
+        this.$q = $q;
+
+        const scope = $root.$new();
+
+        scope.ui = {};
+
+        scope.ok = () => {
+            this.deferred.resolve({filter: scope.ui.filter, caseSensitive: !!scope.ui.caseSensitive});
+
+            this.modal.hide();
+        };
+
+        scope.$hide = () => {
+            this.modal.hide();
+
+            this.deferred.reject();
+        };
+
+        this.modal = $modal({templateUrl: '/scan-filter-input.html', scope, placement: 'center', show: false});
+    }
+
+    open() {
+        this.deferred = this.$q.defer();
+
+        this.modal.$promise.then(this.modal.show);
+
+        return this.deferred.promise;
+    }
+}


[34/52] ignite git commit: Web Console beta-3.

Posted by ak...@apache.org.
http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/frontend/app/modules/states/configuration/clusters/connector.jade
----------------------------------------------------------------------
diff --git a/modules/web-console/frontend/app/modules/states/configuration/clusters/connector.jade b/modules/web-console/frontend/app/modules/states/configuration/clusters/connector.jade
new file mode 100644
index 0000000..baec54f
--- /dev/null
+++ b/modules/web-console/frontend/app/modules/states/configuration/clusters/connector.jade
@@ -0,0 +1,103 @@
+//-
+    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.jade
+
+-var form = 'connector'
+-var model = 'backupItem.connector'
+-var enabled = model + '.enabled'
+-var sslEnabled = enabled + ' && ' + model + '.sslEnabled'
+
+.panel.panel-default(ng-form=form novalidate)
+    .panel-heading(bs-collapse-toggle ng-click='ui.loadPanel("#{form}")')
+        ignite-form-panel-chevron
+        label Connector configuration
+        ignite-form-field-tooltip.tipLabel
+            | Configure HTTP REST configuration to enable HTTP server features
+        ignite-form-revert
+    .panel-collapse(role='tabpanel' bs-collapse-target id=form)
+        .panel-body(ng-if='ui.isPanelLoaded("#{form}")')
+            .col-sm-6
+                .settings-row
+                    +checkbox('Enabled', enabled, '"restEnabled"', 'Flag indicating whether to configure connector configuration')
+                .settings-row
+                    +text-enabled('Jetty configuration path:', model + '.jettyPath', '"connectorJettyPath"', enabled, 'false', 'Input path to Jetty configuration',
+                        'Path, either absolute or relative to IGNITE_HOME, to Jetty XML configuration file<br/>\
+                        Jetty is used to support REST over HTTP protocol for accessing Ignite APIs remotely<br/>\
+                        If not provided, Jetty instance with default configuration will be started picking IgniteSystemProperties.IGNITE_JETTY_HOST and IgniteSystemProperties.IGNITE_JETTY_PORT as host and port respectively')
+                .settings-row
+                    +text-ip-address('TCP host:', model + '.host', '"connectorHost"', enabled, 'IgniteConfiguration#getLocalHost()',
+                        'Host for TCP binary protocol server<br/>\
+                        This can be either an IP address or a domain name<br/>\
+                        If not defined, system - wide local address will be used IgniteConfiguration#getLocalHost()<br/>\
+                        You can also use "0.0.0.0" value to bind to all locally - available IP addresses')
+                .settings-row
+                    +number-min-max('TCP port:', model + '.port', '"connectorPort"', enabled, '11211', '1024', '65535', 'Port for TCP binary protocol server')
+                .settings-row
+                    +number('TCP port range:', model + '.portRange', '"connectorPortRange"', enabled, '100', '1', 'Number of ports for TCP binary protocol server to try if configured port is already in use')
+                .settings-row
+                    +number('Idle query cursor timeout:', model + '.idleQueryCursorTimeout', '"connectorIdleQueryCursorTimeout"', enabled, '600000', '0',
+                        'Reject open query cursors that is not used timeout<br/>\
+                        If no fetch query request come within idle timeout, it will be removed on next check for old query cursors')
+                .settings-row
+                    +number('Idle query cursor check frequency:', model + '.idleQueryCursorCheckFrequency', '"connectorIdleQueryCursorCheckFrequency"', enabled, '60000', '0',
+                        'Idle query cursors check frequency<br/>\
+                        This setting is used to reject open query cursors that is not used')
+                .settings-row
+                    +number('Idle timeout:', model + '.idleTimeout', '"connectorIdleTimeout"', enabled, '7000', '0',
+                        'Idle timeout for REST server<br/>\
+                        This setting is used to reject half - opened sockets<br/>\
+                        If no packets come within idle timeout, the connection is closed')
+                .settings-row
+                    +number('Receive buffer size:', model + '.receiveBufferSize', '"connectorReceiveBufferSize"', enabled, '32768', '0', 'REST TCP server receive buffer size')
+                .settings-row
+                    +number('Send buffer size:', model + '.sendBufferSize', '"connectorSendBufferSize"', enabled, '32768', '0', 'REST TCP server send buffer size')
+                .settings-row
+                    +number('Send queue limit:', model + '.sendQueueLimit', '"connectorSendQueueLimit"', enabled, 'unlimited', '0',
+                        'REST TCP server send queue limit<br/>\
+                        If the limit exceeds, all successive writes will block until the queue has enough capacity')
+                .settings-row
+                    +checkbox-enabled('Direct buffer', model + '.directBuffer', '"connectorDirectBuffer"', enabled,
+                        'Flag indicating whether REST TCP server should use direct buffers<br/>\
+                        A direct buffer is a buffer that is allocated and accessed using native system calls, without using JVM heap<br/>\
+                        Enabling direct buffer may improve performance and avoid memory issues(long GC pauses due to huge buffer size)')
+                .settings-row
+                    +checkbox-enabled('TCP_NODELAY option', model + '.noDelay', '"connectorNoDelay"', enabled,
+                        'Flag indicating whether TCP_NODELAY option should be set for accepted client connections<br/>\
+                        Setting this option reduces network latency and should be enabled in majority of cases<br/>\
+                        For more information, see Socket#setTcpNoDelay(boolean)')
+                .settings-row
+                    +number('Selector count:', model + '.selectorCount', '"connectorSelectorCount"', enabled, 'min(4, availableProcessors)', '1',
+                        'Number of selector threads in REST TCP server<br/>\
+                        Higher value for this parameter may increase throughput, but also increases context switching')
+                .settings-row
+                    +number('Thread pool size:', model + '.threadPoolSize', '"connectorThreadPoolSize"', enabled, 'max(8, availableProcessors) * 2', '1',
+                        'Thread pool size to use for processing of client messages (REST requests)')
+                .settings-row
+                    +java-class('Message interceptor:', model + '.messageInterceptor', '"connectorMessageInterceptor"', enabled, 'false',
+                        'Interceptor allows to transform all objects exchanged via REST protocol<br/>\
+                        For example if you use custom serialisation on client you can write interceptor to transform binary representations received from client to Java objects and later access them from java code directly')
+                .settings-row
+                    +text-enabled('Secret key:', model + '.secretKey', '"connectorSecretKey"', enabled, 'false', 'Specify to enable authentication', 'Secret key to authenticate REST requests')
+                .settings-row
+                    +checkbox-enabled('Enable SSL', model + '.sslEnabled', '"connectorSslEnabled"', enabled, 'Enables/disables SSL for REST TCP binary protocol')
+                .settings-row
+                    +checkbox-enabled('Enable SSL client auth', model + '.sslClientAuth', '"connectorSslClientAuth"', sslEnabled, 'Flag indicating whether or not SSL client authentication is required')
+                .settings-row
+                    +java-class('SSL factory:', model + '.sslFactory', '"connectorSslFactory"', sslEnabled, sslEnabled,
+                        'Instance of Factory that will be used to create an instance of SSLContext for Secure Socket Layer on TCP binary protocol')
+            .col-sm-6
+                +preview-xml-java(model, 'clusterConnector')

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/frontend/app/modules/states/configuration/clusters/deployment.jade
----------------------------------------------------------------------
diff --git a/modules/web-console/frontend/app/modules/states/configuration/clusters/deployment.jade b/modules/web-console/frontend/app/modules/states/configuration/clusters/deployment.jade
new file mode 100644
index 0000000..6cfa82d
--- /dev/null
+++ b/modules/web-console/frontend/app/modules/states/configuration/clusters/deployment.jade
@@ -0,0 +1,113 @@
+//-
+    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.jade
+
+-var form = 'deployment'
+-var model = 'backupItem'
+-var exclude = model + '.peerClassLoadingLocalClassPathExclude'
+-var enabled = 'backupItem.peerClassLoadingEnabled'
+
+.panel.panel-default(ng-form=form novalidate)
+    .panel-heading(bs-collapse-toggle ng-click='ui.loadPanel("#{form}")')
+        ignite-form-panel-chevron
+        label Class deployment
+        ignite-form-field-tooltip.tipLabel
+            | Task and resources deployment in cluster
+        ignite-form-revert
+    .panel-collapse(role='tabpanel' bs-collapse-target id='deployment')
+        .panel-body(ng-if='ui.isPanelLoaded("#{form}")')
+            .col-sm-6
+                .settings-row
+                    +dropdown('Deployment mode:', model + '.deploymentMode', '"deploymentMode"', 'true', 'SHARED',
+                        '[\
+                            {value: "PRIVATE", label: "PRIVATE"},\
+                            {value: "ISOLATED", label: "ISOLATED"}, \
+                            {value: "SHARED", label: "SHARED"},\
+                            {value: "CONTINUOUS", label: "CONTINUOUS"}\
+                        ]',
+                        'Task classes and resources sharing mode<br/>\
+                        The following deployment modes are supported:\
+                        <ul>\
+                            <li>PRIVATE - in this mode deployed classes do not share resources</li>\
+                            <li>ISOLATED - in this mode tasks or classes deployed within the same class loader will share the same instances of resources</li>\
+                            <li>SHARED - same as ISOLATED, but now tasks from different master nodes with the same user version and same class loader will share the same class loader on remote nodes</li>\
+                            <li>CONTINUOUS - same as SHARED deployment mode, but resources will not be undeployed even after all master nodes left grid</li>\
+                        </ul>')
+                .settings-row
+                    +checkbox('Enable peer class loading', model + '.peerClassLoadingEnabled', '"peerClassLoadingEnabled"', 'Enables/disables peer class loading')
+                .settings-row
+                    +number('Missed resources cache size:', model + '.peerClassLoadingMissedResourcesCacheSize', '"peerClassLoadingMissedResourcesCacheSize"', enabled, '100', '0',
+                        'If size greater than 0, missed resources will be cached and next resource request ignored<br/>\
+                        If size is 0, then request for the resource will be sent to the remote node every time this resource is requested')
+                .settings-row
+                    +number('Pool size:', model + '.peerClassLoadingThreadPoolSize', '"peerClassLoadingThreadPoolSize"', enabled, '2', '1', 'Thread pool size to use for peer class loading')
+                .settings-row
+                    +ignite-form-group(ng-model=exclude ng-form=form)
+                        -var uniqueTip = 'Such package already exists'
+
+                        ignite-form-field-label
+                            | Local class path exclude
+                        ignite-form-group-tooltip
+                            | List of packages from the system classpath that need to be peer-to-peer loaded from task originating node<br/>
+                            | '*' is supported at the end of the package name which means that all sub-packages and their classes are included like in Java package import clause
+                        ignite-form-group-add(ng-show='#{enabled}' ng-click='(group.add = [{}])')
+                            | Add package name.
+
+                        .group-content(ng-if=exclude + '.length')
+                            -var model = 'obj.model';
+                            -var name = '"edit" + $index'
+                            -var valid = form + '[' + name + '].$valid'
+                            -var save = exclude + '[$index] = ' + model
+
+                            div(ng-show=enabled)
+                                div(ng-repeat='model in #{exclude} track by $index' ng-init='obj = {}')
+                                    label.col-xs-12.col-sm-12.col-md-12
+                                        .indexField
+                                            | {{ $index+1 }})
+                                        +table-remove-button(exclude, 'Remove package name')
+                                        span(ng-hide='field.edit')
+                                            a.labelFormField(ng-click='#{enabled} && (field.edit = true) && (#{model} = model)') {{ model }}
+                                        span(ng-if='field.edit')
+                                            +table-java-package-field(name, model, exclude, valid, save, false)
+                                                +table-save-button(valid, save, false)
+                                                +unique-feedback(name, uniqueTip)
+
+                            div(ng-hide=enabled)
+                                div(ng-repeat='model in #{exclude} track by $index')
+                                    label.col-xs-12.col-sm-12.col-md-12
+                                        .labelFormField.labelField
+                                            | {{ $index+1 }})
+                                        span.labelFormField
+                                            | {{ model }}
+
+                        .group-content(ng-repeat='field in group.add')
+                            -var model = 'new';
+                            -var name = '"new"'
+                            -var valid = form + '[' + name + '].$valid'
+                            -var save = exclude + '.push(' + model + ')'
+
+                            div(type='internal' name='Package name')
+                                label.col-xs-12.col-sm-12.col-md-12
+                                    +table-java-package-field(name, model, exclude, valid, save, true)
+                                        +table-save-button(valid, save, true)
+                                        +unique-feedback(name, uniqueTip)
+
+
+                        .group-content-empty(ng-if='!(#{exclude}.length) && !group.add.length')
+                            | Not defined
+            .col-sm-6
+                +preview-xml-java(model, 'clusterDeployment')

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/frontend/app/modules/states/configuration/clusters/discovery.jade
----------------------------------------------------------------------
diff --git a/modules/web-console/frontend/app/modules/states/configuration/clusters/discovery.jade b/modules/web-console/frontend/app/modules/states/configuration/clusters/discovery.jade
new file mode 100644
index 0000000..1fdcbec
--- /dev/null
+++ b/modules/web-console/frontend/app/modules/states/configuration/clusters/discovery.jade
@@ -0,0 +1,87 @@
+//-
+    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.jade
+
+-var form = 'discovery'
+-var model = 'backupItem.discovery'
+
+.panel.panel-default(ng-form=form novalidate)
+    .panel-heading(bs-collapse-toggle ng-click='ui.loadPanel("#{form}")')
+        ignite-form-panel-chevron
+        label Discovery
+        ignite-form-field-tooltip.tipLabel
+            | TCP/IP discovery configuration
+        ignite-form-revert
+    .panel-collapse(role='tabpanel' bs-collapse-target id=form)
+        .panel-body(ng-if='ui.isPanelLoaded("#{form}")')
+            .col-sm-6
+                .settings-row
+                    +text-ip-address('Local address:', model + '.localAddress', '"discoLocalAddress"', 'true', '228.1.2.4',
+                        'Local host IP address that discovery SPI uses<br/>\
+                        If not provided a first found non-loopback address will be used')
+                .settings-row
+                    +number-min-max('Local port:', model + '.localPort', '"discoLocalPort"', 'true', '47500', '1024', '65535', 'Local port which node uses')
+                .settings-row
+                    +number('Local port range:', model + '.localPortRange', '"discoLocalPortRange"', 'true', '100', '1', 'Local port range')
+                .settings-row
+                    +java-class('Address resolver:', model + '.addressResolver', '"discoAddressResolver"', 'true', 'false',
+                        'Provides resolution between external and internal addresses')
+                .settings-row
+                    +number('Socket timeout:', model + '.socketTimeout', '"socketTimeout"', 'true', '5000', '0', 'Socket operations timeout')
+                .settings-row
+                    +number('Acknowledgement timeout:', model + '.ackTimeout', '"ackTimeout"', 'true', '5000', '0', 'Message acknowledgement timeout')
+                .settings-row
+                    +number('Max acknowledgement timeout:', model + '.maxAckTimeout', '"maxAckTimeout"', 'true', '600000', '0', 'Maximum message acknowledgement timeout')
+                .settings-row
+                    +number('Network timeout:', model + '.networkTimeout', '"discoNetworkTimeout"', 'true', '5000', '1', 'Timeout to use for network operations')
+                .settings-row
+                    +number('Join timeout:', model + '.joinTimeout', '"joinTimeout"', 'true', '0', '0',
+                        'Join timeout<br/>' +
+                        '0 means wait forever')
+                .settings-row
+                    +number('Thread priority:', model + '.threadPriority', '"threadPriority"', 'true', '10', '1', 'Thread priority for all threads started by SPI')
+                .settings-row
+                    +number('Heartbeat frequency:', model + '.heartbeatFrequency', '"heartbeatFrequency"', 'true', '2000', '1', 'Heartbeat messages issuing frequency')
+                .settings-row
+                    +number('Max heartbeats miss w/o init:', model + '.maxMissedHeartbeats', '"maxMissedHeartbeats"', 'true', '1', '1',
+                        'Max heartbeats count node can miss without initiating status check')
+                .settings-row
+                    +number('Max missed client heartbeats:', model + '.maxMissedClientHeartbeats', '"maxMissedClientHeartbeats"', 'true', '5', '1',
+                        'Max heartbeats count node can miss without failing client node')
+                .settings-row
+                    +number('Topology history:', model + '.topHistorySize', '"topHistorySize"', 'true', '1000', '0', 'Size of topology snapshots history')
+                .settings-row
+                    +java-class('Discovery listener:', model + '.listener', '"discoListener"', 'true', 'false', 'Listener for grid node discovery events')
+                .settings-row
+                    +java-class('Data exchange:', model + '.dataExchange', '"dataExchange"', 'true', 'false', 'Class name of handler for initial data exchange between Ignite nodes')
+                .settings-row
+                    +java-class('Metrics provider:', model + '.metricsProvider', '"metricsProvider"', 'true', 'false', 'Class name of metric provider to discovery SPI')
+                .settings-row
+                    +number('Reconnect count:', model + '.reconnectCount', '"discoReconnectCount"', 'true', '10', '1', 'Reconnect attempts count')
+                .settings-row
+                    +number('Statistics frequency:', model + '.statisticsPrintFrequency', '"statisticsPrintFrequency"', 'true', '0', '1', 'Statistics print frequency')
+                .settings-row
+                    +number('IP finder clean frequency:', model + '.ipFinderCleanFrequency', '"ipFinderCleanFrequency"', 'true', '60000', '1', 'IP finder clean frequency')
+                .settings-row
+                    +java-class('Node authenticator:', model + '.authenticator', '"authenticator"', 'true', 'false', 'Class name of node authenticator implementation')
+                .settings-row
+                    +checkbox('Force server mode', model + '.forceServerMode', '"forceServerMode"', 'Force start TCP/IP discovery in server mode')
+                .settings-row
+                    +checkbox('Client reconnect disabled', model + '.clientReconnectDisabled', '"clientReconnectDisabled"',
+                        'Disable try of client to reconnect after server detected client node failure')
+            .col-sm-6
+                +preview-xml-java(model, 'clusterDiscovery')

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/frontend/app/modules/states/configuration/clusters/events.jade
----------------------------------------------------------------------
diff --git a/modules/web-console/frontend/app/modules/states/configuration/clusters/events.jade b/modules/web-console/frontend/app/modules/states/configuration/clusters/events.jade
new file mode 100644
index 0000000..412714c
--- /dev/null
+++ b/modules/web-console/frontend/app/modules/states/configuration/clusters/events.jade
@@ -0,0 +1,37 @@
+//-
+    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.jade
+
+-var form = 'events'
+-var model = 'backupItem'
+
+.panel.panel-default(ng-form=form novalidate)
+    .panel-heading(bs-collapse-toggle ng-click='ui.loadPanel("#{form}")')
+        ignite-form-panel-chevron
+        label Events
+        ignite-form-field-tooltip.tipLabel
+            | Grid events are used for notification about what happens within the grid
+        ignite-form-revert
+    .panel-collapse(role='tabpanel' bs-collapse-target id=form)
+        .panel-body(ng-if='ui.isPanelLoaded("#{form}")')
+            .col-sm-6
+                .settings-row
+                    +dropdown-multiple('Include type:', model + '.includeEventTypes', '"includeEventTypes"', true, 'Choose recorded event types', '', 'eventGroups',
+                        'Array of event types, which will be recorded by GridEventStorageManager#record(Event)<br/>\
+                        Note, that either the include event types or the exclude event types can be established')
+            .col-sm-6
+                +preview-xml-java(model, 'clusterEvents')

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/frontend/app/modules/states/configuration/clusters/failover.jade
----------------------------------------------------------------------
diff --git a/modules/web-console/frontend/app/modules/states/configuration/clusters/failover.jade b/modules/web-console/frontend/app/modules/states/configuration/clusters/failover.jade
new file mode 100644
index 0000000..85f0f54
--- /dev/null
+++ b/modules/web-console/frontend/app/modules/states/configuration/clusters/failover.jade
@@ -0,0 +1,72 @@
+//-
+    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.jade
+
+-var model = 'backupItem'
+-var form = 'failoverSpi'
+-var failoverSpi = model + '.failoverSpi'
+-var failoverCustom = 'failover.kind === "Custom"'
+
+.panel.panel-default(ng-form=form novalidate)
+    .panel-heading(bs-collapse-toggle ng-click='ui.loadPanel("#{form}")')
+        ignite-form-panel-chevron
+        label Failover configuration
+        ignite-form-field-tooltip.tipLabel
+            | Failover SPI provides ability to supply custom logic for handling failed execution of a grid job
+        ignite-form-revert
+    .panel-collapse(role='tabpanel' bs-collapse-target id=form)
+        .panel-body(ng-if='ui.isPanelLoaded("#{form}")')
+            .col-sm-6
+                .settings-row(ng-init='failoverSpiTbl={type: "failoverSpi", model: "failoverSpi", focusId: "kind", ui: "failover-table"}')
+                    +ignite-form-group()
+                        ignite-form-field-label
+                            | Failover SPI configurations
+                        ignite-form-group-tooltip
+                            | Failover SPI configurations
+                        ignite-form-group-add(ng-click='tableNewItem(failoverSpiTbl)')
+                            | Add failover SPI
+                        .group-content-empty(ng-if='!(#{failoverSpi} && #{failoverSpi}.length > 0)')
+                            | Not defined
+                        .group-content(ng-show='#{failoverSpi} && #{failoverSpi}.length > 0' ng-repeat='failover in #{failoverSpi} track by $index')
+                            hr(ng-if='$index != 0')
+                            .settings-row
+                                +dropdown('Failover SPI:', 'failover.kind', '"failoverKind" + $index', 'true', 'Choose Failover SPI', '[\
+                                        {value: "JobStealing", label: "Job stealing"},\
+                                        {value: "Never", label: "Never"},\
+                                        {value: "Always", label: "Always"},\
+                                        {value: "Custom", label: "Custom"}\
+                                    ]', 'Provides ability to supply custom logic for handling failed execution of a grid job\
+                                    <ul>\
+                                        <li>Job stealing - Supports job stealing from over-utilized nodes to under-utilized nodes</li>\
+                                        <li>Never - Jobs are ordered as they arrived</li>\
+                                        <li>Always - Jobs are first ordered by their priority</li>\
+                                        <li>Custom - Jobs are activated immediately on arrival to mapped node</li>\
+                                        <li>Default - Default FailoverSpi implementation</li>\
+                                    </ul>')
+
+                                    +table-remove-button(failoverSpi, 'Remove Failover SPI')
+                            .settings-row(ng-show='failover.kind === "JobStealing"')
+                                +number('Maximum failover attempts:', 'failover.JobStealing.maximumFailoverAttempts', '"jsMaximumFailoverAttempts" + $index', 'true', '5', '0',
+                                    'Maximum number of attempts to execute a failed job on another node')
+                            .settings-row(ng-show='failover.kind === "Always"')
+                                +number('Maximum failover attempts:', 'failover.Always.maximumFailoverAttempts', '"alwaysMaximumFailoverAttempts" + $index', 'true', '5', '0',
+                                    'Maximum number of attempts to execute a failed job on another node')
+                            .settings-row(ng-show=failoverCustom)
+                                +java-class('SPI implementation', 'failover.Custom.class', '"failoverSpiClass" + $index', 'true', failoverCustom,
+                                    'Custom FailoverSpi implementation class name.')
+            .col-sm-6
+                +preview-xml-java(model, 'clusterFailover')

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/frontend/app/modules/states/configuration/clusters/general.jade
----------------------------------------------------------------------
diff --git a/modules/web-console/frontend/app/modules/states/configuration/clusters/general.jade b/modules/web-console/frontend/app/modules/states/configuration/clusters/general.jade
new file mode 100644
index 0000000..d0d390f
--- /dev/null
+++ b/modules/web-console/frontend/app/modules/states/configuration/clusters/general.jade
@@ -0,0 +1,73 @@
+//-
+    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.jade
+
+-var form = 'general'
+-var model = 'backupItem'
+-var modelDiscoveryKind = model + '.discovery.kind'
+
+.panel.panel-default(ng-form=form novalidate)
+    .panel-heading(bs-collapse-toggle)
+        ignite-form-panel-chevron
+        label General
+        ignite-form-revert
+    .panel-collapse(role='tabpanel' bs-collapse-target id=form)
+        .panel-body
+            .col-sm-6
+                .settings-row
+                    +text('Name:', model + '.name', '"clusterName"', 'true', 'Input name', 'Grid name allows to indicate to what grid this particular grid instance belongs to')
+                .settings-row
+                    +caches(model, 'Select caches to start in cluster or add a new cache')
+                .settings-row
+                    +text-ip-address('Local host:', model + '.localHost', '"localHost"', 'true', '0.0.0.0',
+                        'System-wide local address or host for all Ignite components to bind to<br/>\
+                        If not defined then Ignite tries to use local wildcard address<br/>\
+                        That means that all services will be available on all network interfaces of the host machine')
+                .settings-row
+                    +dropdown('Discovery:', model + '.discovery.kind', '"discovery"', 'true', 'Choose discovery', 'discoveries',
+                        'Discovery allows to discover remote nodes in grid\
+                        <ul>\
+                            <li>Static IPs - IP Finder which works only with pre configured list of IP addresses specified</li>\
+                            <li>Multicast - Multicast based IP finder</li>\
+                            <li>AWS S3 - AWS S3 based IP finder that automatically discover cluster nodes on Amazon EC2 cloud</li>\
+                            <li>Apache jclouds - Apache jclouds multi cloud toolkit based IP finder for cloud platforms with unstable IP addresses</li>\
+                            <li>Google cloud storage - Google Cloud Storage based IP finder that automatically discover cluster nodes on Google Compute Engine cluster</li>\
+                            <li>JDBC - JDBC based IP finder that use database to store node IP addres</li>\
+                            <li>Shared filesystem - Shared filesystem based IP finder that use file to store node IP address</li>\
+                            <li>Apache ZooKeeper - Apache ZooKeeper based IP finder when you use ZooKeeper to coordinate your distributed environment</li>\
+                        </ul>')
+                .settings-row
+                    .panel-details
+                        div(ng-if='#{modelDiscoveryKind} === "Cloud"')
+                            include ./general/discovery/cloud.jade
+                        div(ng-if='#{modelDiscoveryKind} === "GoogleStorage"')
+                            include ./general/discovery/google.jade
+                        div(ng-if='#{modelDiscoveryKind} === "Jdbc"')
+                            include ./general/discovery/jdbc.jade
+                        div(ng-if='#{modelDiscoveryKind} === "Multicast"')
+                            include ./general/discovery/multicast.jade
+                        div(ng-if='#{modelDiscoveryKind} === "S3"')
+                            include ./general/discovery/s3.jade
+                        div(ng-if='#{modelDiscoveryKind} === "SharedFs"')
+                            include ./general/discovery/shared.jade
+                        div(ng-if='#{modelDiscoveryKind} === "Vm"')
+                            include ./general/discovery/vm.jade
+                        div(ng-if='#{modelDiscoveryKind} === "ZooKeeper"')
+                            include ./general/discovery/zookeeper.jade
+            .col-sm-6
+                -var model = 'backupItem'
+                +preview-xml-java(model, 'clusterCaches', 'caches')

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/frontend/app/modules/states/configuration/clusters/general/discovery/cloud.jade
----------------------------------------------------------------------
diff --git a/modules/web-console/frontend/app/modules/states/configuration/clusters/general/discovery/cloud.jade b/modules/web-console/frontend/app/modules/states/configuration/clusters/general/discovery/cloud.jade
new file mode 100644
index 0000000..640c78c
--- /dev/null
+++ b/modules/web-console/frontend/app/modules/states/configuration/clusters/general/discovery/cloud.jade
@@ -0,0 +1,134 @@
+//-
+    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.jade
+
+-var discoveryKind = 'Cloud'
+-var required = 'backupItem.discovery.kind == "' + discoveryKind + '"'
+-var model = 'backupItem.discovery.Cloud'
+-var regions = model + '.regions'
+-var zones = model + '.zones'
+-var formRegions = 'discoveryCloudRegions'
+-var formZones = 'discoveryCloudZones'
+
+div
+    .details-row
+        +text('Credential:', model + '.credential', '"credential"', 'false', 'Input cloud credential',
+            'Credential that is used during authentication on the cloud<br/>\
+            Depending on a cloud platform it can be a password or access key')
+    .details-row
+        +text('Path to credential:', model + '.credentialPath', '"credentialPath"', 'false', 'Input pathto credential',
+            'Path to a credential that is used during authentication on the cloud<br/>\
+            Access key or private key should be stored in a plain or PEM file without a passphrase')
+    .details-row
+        +text('Identity:', model + '.identity', '"' + discoveryKind + 'Identity"', required, 'Input identity',
+            'Identity that is used as a user name during a connection to the cloud<br/>\
+            Depending on a cloud platform it can be an email address, user name, etc')
+    .details-row
+        +text('Provider:', model + '.provider', '"' + discoveryKind + 'Provider"', required, 'Input provider', 'Cloud provider to use')
+    .details-row
+        -var form = formRegions;
+        +ignite-form-group(ng-model=regions ng-form=form)
+            -var uniqueTip = 'Such region already exists!'
+
+            ignite-form-field-label
+                | Regions
+            ignite-form-group-tooltip
+                | List of regions where VMs are located#[br]
+                | If the regions are not set then every region, that a cloud provider has, will be investigated. This could lead to significant performance degradation#[br]
+                | Note, that some cloud providers, like Google Compute Engine, doesn't have a notion of a region. For such providers regions are redundant
+            ignite-form-group-add(ng-click='group.add = [{}]')
+                | Add new region
+
+            .group-content(ng-if='#{regions}.length')
+                -var model = 'field.model';
+                -var name = '"edit" + $index'
+                -var valid = form + '[' + name + '].$valid'
+                -var save = regions + '[$index] = ' + model
+
+                div(ng-repeat='model in #{regions} track by $index')
+                    label.col-xs-12.col-sm-12.col-md-12(ng-init='field = {}')
+                        .indexField
+                            | {{ $index+1 }})
+                        +table-remove-button(regions, 'Remove region')
+                        span(ng-hide='field.edit')
+                            a.labelFormField(ng-click='field.edit = true; #{model} = model;') {{ model }}
+                        span(ng-if='field.edit')
+                            +table-text-field(name, model, regions, valid, save, 'Region name', false)
+                                +table-save-button(valid, save, false)
+                                +unique-feedback(name, uniqueTip)
+
+            .group-content(ng-repeat='field in group.add')
+                -var model = 'field.new';
+                -var name = '"new"'
+                -var valid = form + '[' + name + '].$valid'
+                -var save = regions + '.push(' + model + ')'
+
+                div
+                    label.col-xs-12.col-sm-12.col-md-12
+                        +table-text-field(name, model, regions, valid, save, 'Region name', true)
+                            +table-save-button(valid, save, false)
+                            +unique-feedback(name, uniqueTip)
+
+            .group-content-empty(ng-if='!(#{regions}.length) && !group.add.length')
+                | Not defined
+    .details-row
+        -var form = formZones;
+        +ignite-form-group(ng-model=zones ng-form=form)
+            -var uniqueTip = 'Such zone already exists!'
+
+            ignite-form-field-label
+                | Zones
+            ignite-form-group-tooltip
+                | List of zones where VMs are located#[br]
+                | If the zones are not set then every zone from specified regions, will be taken into account#[br]
+                | Note, that some cloud providers, like Rackspace, doesn't have a notion of a zone. For such providers zones are redundant
+            ignite-form-group-add(ng-click='group.add = [{}]')
+                | Add new zone
+
+            -var form = formZones;
+            .group-content(ng-if='#{zones}.length')
+                -var model = 'field.model';
+                -var name = '"edit" + $index'
+                -var valid = form + '[' + name + '].$valid'
+                -var save = zones + '[$index] = ' + model
+
+                div(ng-repeat='model in #{zones} track by $index')
+                    label.col-xs-12.col-sm-12.col-md-12(ng-init='field = {}')
+                        .indexField
+                            | {{ $index+1 }})
+                        +table-remove-button(zones, 'Remove zone')
+                        span(ng-hide='field.edit')
+                            a.labelFormField(ng-click='field.edit = true; #{model} = model;') {{ model }}
+                        span(ng-if='field.edit')
+                            +table-text-field(name, model, zones, valid, save, 'Zone name', false)
+                                +table-save-button(valid, save, false)
+                                +unique-feedback(name, uniqueTip)
+
+            .group-content(ng-repeat='field in group.add')
+                -var model = 'field.new';
+                -var name = '"new"'
+                -var valid = form + '[' + name + '].$valid'
+                -var save = zones + '.push(' + model + ')'
+
+                div
+                    label.col-xs-12.col-sm-12.col-md-12
+                        +table-text-field(name, model, zones, valid, save, 'Zone name', true)
+                            +table-save-button(valid, save, true)
+                            +unique-feedback(name, uniqueTip)
+
+            .group-content-empty(ng-if='!(#{zones}.length) && !group.add.length')
+                | Not defined

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/frontend/app/modules/states/configuration/clusters/general/discovery/google.jade
----------------------------------------------------------------------
diff --git a/modules/web-console/frontend/app/modules/states/configuration/clusters/general/discovery/google.jade b/modules/web-console/frontend/app/modules/states/configuration/clusters/general/discovery/google.jade
new file mode 100644
index 0000000..b1a5958
--- /dev/null
+++ b/modules/web-console/frontend/app/modules/states/configuration/clusters/general/discovery/google.jade
@@ -0,0 +1,38 @@
+//-
+    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.jade
+
+
+-var discoveryKind = 'GoogleStorage'
+-var required = 'backupItem.discovery.kind == "' + discoveryKind + '"'
+-var model = 'backupItem.discovery.GoogleStorage'
+
+div
+    .details-row
+        +text('Project name:', model + '.projectName', '"' + discoveryKind + 'ProjectName"', required, 'Input project name', '' +
+            'Google Cloud Platforms project name<br/>\
+            Usually this is an auto generated project number(ex. 208709979073) that can be found in "Overview" section of Google Developer Console')
+    .details-row
+        +text('Bucket name:', model + '.bucketName', '"' + discoveryKind + 'BucketName"', required, 'Input bucket name',
+            'Google Cloud Storage bucket name<br/>\
+            If the bucket does not exist Ignite will automatically create it<br/>\
+            However the name must be unique across whole Google Cloud Storage and Service Account Id must be authorized to perform this operation')
+    .details-row
+        +text('Private key path:', model + '.serviceAccountP12FilePath', '"' + discoveryKind + 'ServiceAccountP12FilePath"', required, 'Input private key path',
+            'Full path to the private key in PKCS12 format of the Service Account')
+    .details-row
+        +text('Account id:', model + '.serviceAccountId', '"' + discoveryKind + 'ServiceAccountId"', required, 'Input account id', 'Service account ID (typically an e-mail address)')

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/frontend/app/modules/states/configuration/clusters/general/discovery/jdbc.jade
----------------------------------------------------------------------
diff --git a/modules/web-console/frontend/app/modules/states/configuration/clusters/general/discovery/jdbc.jade b/modules/web-console/frontend/app/modules/states/configuration/clusters/general/discovery/jdbc.jade
new file mode 100644
index 0000000..42cf697
--- /dev/null
+++ b/modules/web-console/frontend/app/modules/states/configuration/clusters/general/discovery/jdbc.jade
@@ -0,0 +1,32 @@
+//-
+    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.jade
+include ../../../../../../../app/helpers/jade/mixins.jade
+
+-var model = 'backupItem.discovery.Jdbc'
+-var required = 'backupItem.discovery.kind === "Jdbc"'
+
+div
+    .details-row
+        +checkbox('DB schema should be initialized by Ignite', model + '.initSchema', '"initSchema"',
+            'Flag indicating whether DB schema should be initialized by Ignite or was explicitly created by user')
+    .details-row
+        +text('Data source bean name:', model + '.dataSourceBean',
+            '"dataSourceBean"', required, 'Input bean name', 'Name of the data source bean in Spring context')
+    .details-row
+        +dialect('Dialect:', model + '.dialect', '"dialect"', required,
+            'Dialect of SQL implemented by a particular RDBMS:', 'Generic JDBC dialect', 'Choose JDBC dialect')

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/frontend/app/modules/states/configuration/clusters/general/discovery/multicast.jade
----------------------------------------------------------------------
diff --git a/modules/web-console/frontend/app/modules/states/configuration/clusters/general/discovery/multicast.jade b/modules/web-console/frontend/app/modules/states/configuration/clusters/general/discovery/multicast.jade
new file mode 100644
index 0000000..829fbaa
--- /dev/null
+++ b/modules/web-console/frontend/app/modules/states/configuration/clusters/general/discovery/multicast.jade
@@ -0,0 +1,99 @@
+//-
+    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.jade
+
+-var form = 'general'
+-var model = 'backupItem.discovery.Multicast'
+-var addresses = model + '.addresses'
+
+div
+    .details-row
+        +text-ip-address('IP address:', model + '.multicastGroup', '"multicastGroup"', 'true', '228.1.2.4', 'IP address of multicast group')
+    .details-row
+        +number-min-max('Port number:', model + '.multicastPort', '"multicastPort"', 'true', '47400', '0', '65535', 'Port number which multicast messages are sent to')
+    .details-row
+        +number('Waits for reply:', model + '.responseWaitTime', '"responseWaitTime"', 'true', '500', '0',
+            'Time in milliseconds IP finder waits for reply to multicast address request')
+    .details-row
+        +number('Attempts count:', model + '.addressRequestAttempts', '"addressRequestAttempts"', 'true', '2', '0',
+            'Number of attempts to send multicast address request<br/>\
+            IP finder re - sends request only in case if no reply for previous request is received')
+    .details-row
+        +text-ip-address('Local address:', model + '.localAddress', '"localAddress"', 'true', '0.0.0.0',
+            'Local host address used by this IP finder<br/>\
+            If provided address is non - loopback then multicast socket is bound to this interface<br/>\
+            If local address is not set or is any local address then IP finder creates multicast sockets for all found non - loopback addresses')
+    .details-row
+        -var form = 'discoveryMulticastAddresses';
+
+        +ignite-form-group(ng-model=addresses ng-form=form)
+            -var uniqueTip = 'Such IP address already exists!'
+            -var ipAddressTip = 'Invalid IP address!'
+
+            ignite-form-field-label
+                | Addresses
+            ignite-form-group-tooltip
+                | Addresses may be represented as follows:#[br]
+                ul: li IP address (e.g. 127.0.0.1, 9.9.9.9, etc)
+                    li IP address and port (e.g. 127.0.0.1:47500, 9.9.9.9:47501, etc)
+                    li IP address and port range (e.g. 127.0.0.1:47500..47510, 9.9.9.9:47501..47504, etc)
+                    li Hostname (e.g. host1.com, host2, etc)
+                    li Hostname and port (e.g. host1.com:47500, host2:47502, etc)
+                    li Hostname and port range (e.g. host1.com:47500..47510, host2:47502..47508, etc)
+                | If port is 0 or not provided then default port will be used (depends on discovery SPI configuration)#[br]
+                | If port range is provided (e.g. host:port1..port2) the following should be considered:#[br]
+                ul: li port1 &lt; port2 should be true
+                    li Both port1 and port2 should be greater than 0
+            ignite-form-group-add(ng-click='group.add = [{}]')
+                | Add new address
+
+            .group-content(ng-if='#{addresses}.length')
+                -var model = 'obj.model';
+                -var name = '"edit" + $index'
+                -var valid = form + '[' + name + '].$valid'
+                -var save = addresses + '[$index] = ' + model
+
+                div(ng-repeat='model in #{addresses} track by $index' ng-init='obj = {}')
+                    label.col-xs-12.col-sm-12.col-md-12
+                        .indexField
+                            | {{ $index+1 }})
+                        +table-remove-button(addresses, 'Remove address')
+
+                        +ignite-form-field-down(ng-if='!$last' ng-hide='field.edit' data-ng-model='model' data-models=addresses)
+                        +ignite-form-field-up(ng-if='!$first' ng-hide='field.edit' data-ng-model='model' data-models=addresses)
+
+                        span(ng-hide='field.edit')
+                            a.labelFormField(ng-click='field.edit = true; #{model} = model;') {{ model }}
+                        span(ng-if='field.edit')
+                            +table-address-field(name, model, addresses, valid, save, false, true)
+                                +table-save-button(valid, save, false)
+                                +unique-feedback(name, uniqueTip)
+
+            .group-content(ng-repeat='field in group.add')
+                -var model = 'new';
+                -var name = '"new"'
+                -var valid = form + '[' + name + '].$valid'
+                -var save = addresses + '.push(' + model + ')'
+
+                div
+                    label.col-xs-12.col-sm-12.col-md-12
+                        +table-address-field(name, model, addresses, valid, save, true, true)
+                            +table-save-button(valid, save, true)
+                            +unique-feedback(name, uniqueTip)
+
+            .group-content-empty(ng-if='!(#{addresses}.length) && !group.add.length')
+                | Not defined

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/frontend/app/modules/states/configuration/clusters/general/discovery/s3.jade
----------------------------------------------------------------------
diff --git a/modules/web-console/frontend/app/modules/states/configuration/clusters/general/discovery/s3.jade b/modules/web-console/frontend/app/modules/states/configuration/clusters/general/discovery/s3.jade
new file mode 100644
index 0000000..e255f20
--- /dev/null
+++ b/modules/web-console/frontend/app/modules/states/configuration/clusters/general/discovery/s3.jade
@@ -0,0 +1,27 @@
+//-
+    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.jade
+
+-var discoveryKind = 'S3'
+-var required = 'backupItem.discovery.kind == "' + discoveryKind + '"'
+-var model = 'backupItem.discovery.S3'
+
+div
+    .details-row
+        +text('Bucket name:', model + '.bucketName', '"' + discoveryKind + 'BucketName"', required, 'Input bucket name', 'Bucket name for IP finder')
+    .details-row
+        label Note, AWS credentials will be generated as stub

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/frontend/app/modules/states/configuration/clusters/general/discovery/shared.jade
----------------------------------------------------------------------
diff --git a/modules/web-console/frontend/app/modules/states/configuration/clusters/general/discovery/shared.jade b/modules/web-console/frontend/app/modules/states/configuration/clusters/general/discovery/shared.jade
new file mode 100644
index 0000000..2a949a5
--- /dev/null
+++ b/modules/web-console/frontend/app/modules/states/configuration/clusters/general/discovery/shared.jade
@@ -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.
+
+include ../../../../../../../app/helpers/jade/mixins.jade
+
+-var model = 'backupItem.discovery.SharedFs'
+
+div
+    .details-row
+        +text('File path:', model + '.path', '"path"', 'false', 'disco/tcp', 'Shared path')

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/frontend/app/modules/states/configuration/clusters/general/discovery/vm.jade
----------------------------------------------------------------------
diff --git a/modules/web-console/frontend/app/modules/states/configuration/clusters/general/discovery/vm.jade b/modules/web-console/frontend/app/modules/states/configuration/clusters/general/discovery/vm.jade
new file mode 100644
index 0000000..6588e6a
--- /dev/null
+++ b/modules/web-console/frontend/app/modules/states/configuration/clusters/general/discovery/vm.jade
@@ -0,0 +1,79 @@
+//-
+    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.jade
+
+-var model = 'backupItem.discovery.Vm'
+-var addresses = model + '.addresses'
+-var form = 'discoveryVmAddresses'
+
+.details-row
+    +ignite-form-group(ng-form=form ng-model=addresses)
+        -var uniqueTip = 'Such IP address already exists!'
+
+        ignite-form-field-label
+            | Addresses
+        ignite-form-group-tooltip
+            | Addresses may be represented as follows:
+            ul: li IP address (e.g. 127.0.0.1, 9.9.9.9, etc)
+                li IP address and port (e.g. 127.0.0.1:47500, 9.9.9.9:47501, etc)
+                li IP address and port range (e.g. 127.0.0.1:47500..47510, 9.9.9.9:47501..47504, etc)
+                li Hostname (e.g. host1.com, host2, etc)
+                li Hostname and port (e.g. host1.com:47500, host2:47502, etc)
+                li Hostname and port range (e.g. host1.com:47500..47510, host2:47502..47508, etc)
+            | If port is 0 or not provided then default port will be used (depends on discovery SPI configuration)#[br]
+            | If port range is provided (e.g. host:port1..port2) the following should be considered:
+            ul: li port1 &lt; port2 should be true
+                li Both port1 and port2 should be greater than 0
+        ignite-form-group-add(ng-click='group.add = [{}]')
+            | Add new address
+
+        .group-content(ng-if='#{addresses}.length')
+            -var model = 'obj.model';
+            -var name = '"edit" + $index'
+            -var valid = form + '[' + name + '].$valid'
+            -var save = addresses + '[$index] = ' + model
+
+            div(ng-repeat='model in #{addresses} track by $index' ng-init='obj = {}')
+                label.col-xs-12.col-sm-12.col-md-12
+                    .indexField
+                        | {{ $index+1 }})
+                    +table-remove-button(addresses, 'Remove address')
+
+                    +ignite-form-field-down(ng-if='!$last' ng-hide='field.edit' data-ng-model='model' data-models=addresses)
+                    +ignite-form-field-up(ng-if='!$first' ng-hide='field.edit' data-ng-model='model' data-models=addresses)
+
+                    span(ng-hide='field.edit')
+                        a.labelFormField(ng-click='field.edit = true; #{model} = model;') {{ model }}
+                    span(ng-if='field.edit')
+                        +table-address-field(name, model, addresses, valid, save, false, true)
+                            +table-save-button(valid, save, false)
+                            +unique-feedback(name, uniqueTip)
+
+        .group-content(ng-repeat='field in group.add')
+            -var model = 'new';
+            -var name = '"new"'
+            -var valid = form + '[' + name + '].$valid'
+            -var save = addresses + '.push(' + model + ')'
+
+            div
+                label.col-xs-12.col-sm-12.col-md-12
+                    +table-address-field(name, model, addresses, valid, save, true, true)
+                        +table-save-button(valid, save, true)
+                        +unique-feedback(name, uniqueTip)
+
+        .group-content-empty(id='addresses' ng-if='!(#{addresses}.length) && !group.add.length')
+                | Not defined

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/frontend/app/modules/states/configuration/clusters/general/discovery/zookeeper.jade
----------------------------------------------------------------------
diff --git a/modules/web-console/frontend/app/modules/states/configuration/clusters/general/discovery/zookeeper.jade b/modules/web-console/frontend/app/modules/states/configuration/clusters/general/discovery/zookeeper.jade
new file mode 100644
index 0000000..afd3ecd
--- /dev/null
+++ b/modules/web-console/frontend/app/modules/states/configuration/clusters/general/discovery/zookeeper.jade
@@ -0,0 +1,83 @@
+//-
+    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.jade
+
+-var form = 'general'
+-var discoveryKind = 'ZooKeeper'
+-var required = 'backupItem.discovery.kind == "' + discoveryKind + '"'
+-var model = 'backupItem.discovery.ZooKeeper'
+-var modelRetryPolicyKind = model + '.retryPolicy.kind'
+
+div
+    .details-row
+        +java-class('Curator:', model + '.curator', '"curator"', 'true', 'false',
+            'The Curator framework in use<br/>\
+            By default generates curator of org.apache.curator. framework.imps.CuratorFrameworkImpl\
+            class with configured connect string, retry policy, and default session and connection timeouts')
+    .details-row
+        +text('Connect string:', model + '.zkConnectionString', '"' + discoveryKind + 'ConnectionString"', required, 'host:port[chroot][,host:port[chroot]]',
+            'When "IGNITE_ZK_CONNECTION_STRING" system property is not configured this property will be used')
+    .details-row
+        +dropdown('Retry policy:', model + '.retryPolicy.kind', '"retryPolicy"', 'true', 'Default',
+            '[\
+                {value: "ExponentialBackoff", label: "Exponential backoff"},\
+                {value: "BoundedExponentialBackoff", label: "Bounded exponential backoff"},\
+                {value: "UntilElapsed", label: "Until elapsed"},\
+                {value: "NTimes", label: "Max number of times"},\
+                {value: "OneTime", label: "Only once"},\
+                {value: "Forever", label: "Always allow retry"},\
+                {value: "Custom", label: "Custom"},\
+                {value: undefined, label: "Default"}\
+            ]',
+            'Available retry policies:\
+            <ul>\
+                <li>Exponential backoff - retries a set number of times with increasing sleep time between retries</li>\
+                <li>Bounded exponential backoff - retries a set number of times with an increasing (up to a maximum bound) sleep time between retries</li>\
+                <li>Until elapsed - retries until a given amount of time elapses</li>\
+                <li>Max number of times - retries a max number of times</li>\
+                <li>Only once - retries only once</li>\
+                <li>Always allow retry - retries infinitely</li>\
+                <li>Custom - custom retry policy implementation</li>\
+                <li>Default - exponential backoff retry policy with configured base sleep time equal to 1000ms and max retry count equal to 10</li>\
+            </ul>')
+    .details-row(ng-show='#{model}.retryPolicy.kind')
+        .panel-details
+                div(ng-show='#{modelRetryPolicyKind} === "ExponentialBackoff"')
+                    include ./zookeeper/retrypolicy/exponential-backoff.jade
+                div(ng-show='#{modelRetryPolicyKind} === "BoundedExponentialBackoff"')
+                    include ./zookeeper/retrypolicy/bounded-exponential-backoff.jade
+                div(ng-show='#{modelRetryPolicyKind} === "UntilElapsed"')
+                    include ./zookeeper/retrypolicy/until-elapsed.jade
+                div(ng-show='#{modelRetryPolicyKind} === "NTimes"')
+                    include ./zookeeper/retrypolicy/n-times.jade
+                div(ng-show='#{modelRetryPolicyKind} === "OneTime"')
+                    include ./zookeeper/retrypolicy/one-time.jade
+                div(ng-show='#{modelRetryPolicyKind} === "Forever"')
+                    include ./zookeeper/retrypolicy/forever.jade
+                div(ng-show='#{modelRetryPolicyKind} === "Custom"')
+                    include ./zookeeper/retrypolicy/custom.jade
+    .details-row
+        +text('Base path:', model + '.basePath', '"basePath"', 'false', '/services', 'Base path for service registration')
+    .details-row
+        +text('Service name:', model + '.serviceName', '"serviceName"', 'false', 'ignite',
+            'Service name to use, as defined by Curator&#39;s ServiceDiscovery recipe<br/>\
+            In physical ZooKeeper terms, it represents the node under basePath, under which services will be registered')
+    .details-row
+        +checkbox('Allow duplicate registrations', model + '.allowDuplicateRegistrations', '"allowDuplicateRegistrations"',
+            'Whether to register each node only once, or if duplicate registrations are allowed<br/>\
+            Nodes will attempt to register themselves, plus those they know about<br/>\
+            By default, duplicate registrations are not allowed, but you might want to set this property to <b>true</b> if you have multiple network interfaces or if you are facing troubles')

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/frontend/app/modules/states/configuration/clusters/general/discovery/zookeeper/retrypolicy/bounded-exponential-backoff.jade
----------------------------------------------------------------------
diff --git a/modules/web-console/frontend/app/modules/states/configuration/clusters/general/discovery/zookeeper/retrypolicy/bounded-exponential-backoff.jade b/modules/web-console/frontend/app/modules/states/configuration/clusters/general/discovery/zookeeper/retrypolicy/bounded-exponential-backoff.jade
new file mode 100644
index 0000000..5e4bbda
--- /dev/null
+++ b/modules/web-console/frontend/app/modules/states/configuration/clusters/general/discovery/zookeeper/retrypolicy/bounded-exponential-backoff.jade
@@ -0,0 +1,27 @@
+//-
+    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.jade
+
+-var model = 'backupItem.discovery.ZooKeeper.retryPolicy.BoundedExponentialBackoff'
+
+div
+    .details-row
+        +number('Base interval:', model + '.baseSleepTimeMs', '"beBaseSleepTimeMs"', 'true', '1000', '0', 'Initial amount of time in ms to wait between retries')
+    .details-row
+        +number('Max interval:', model + '.maxSleepTimeMs', '"beMaxSleepTimeMs"', 'true', 'Integer.MAX_VALUE', '0', 'Max time in ms to sleep on each retry')
+    .details-row
+        +number-min-max('Max retries:', model + '.maxRetries', '"beMaxRetries"', 'true', '10', '0', '29', 'Max number of times to retry')

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/frontend/app/modules/states/configuration/clusters/general/discovery/zookeeper/retrypolicy/custom.jade
----------------------------------------------------------------------
diff --git a/modules/web-console/frontend/app/modules/states/configuration/clusters/general/discovery/zookeeper/retrypolicy/custom.jade b/modules/web-console/frontend/app/modules/states/configuration/clusters/general/discovery/zookeeper/retrypolicy/custom.jade
new file mode 100644
index 0000000..3dcf514
--- /dev/null
+++ b/modules/web-console/frontend/app/modules/states/configuration/clusters/general/discovery/zookeeper/retrypolicy/custom.jade
@@ -0,0 +1,24 @@
+//-
+    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.jade
+
+-var model = 'backupItem.discovery.ZooKeeper.retryPolicy'
+-var retry = model + '.Custom'
+-var required = 'backupItem.discovery.kind === "ZooKeeper" && backupItem.discovery.ZooKeeper.retryPolicy.kind === "Custom"'
+
+.details-row
+    +java-class('Class name:', retry + '.className', '"customClassName"', 'true', required, 'Custom retry policy implementation class name')

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/frontend/app/modules/states/configuration/clusters/general/discovery/zookeeper/retrypolicy/exponential-backoff.jade
----------------------------------------------------------------------
diff --git a/modules/web-console/frontend/app/modules/states/configuration/clusters/general/discovery/zookeeper/retrypolicy/exponential-backoff.jade b/modules/web-console/frontend/app/modules/states/configuration/clusters/general/discovery/zookeeper/retrypolicy/exponential-backoff.jade
new file mode 100644
index 0000000..618683c
--- /dev/null
+++ b/modules/web-console/frontend/app/modules/states/configuration/clusters/general/discovery/zookeeper/retrypolicy/exponential-backoff.jade
@@ -0,0 +1,27 @@
+//-
+    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.jade
+
+-var model = 'backupItem.discovery.ZooKeeper.retryPolicy.ExponentialBackoff'
+
+div
+    .details-row
+        +number('Base interval:', model + '.baseSleepTimeMs', '"expBaseSleepTimeMs"', 'true', '1000', '0', 'Initial amount of time in ms to wait between retries')
+    .details-row
+        +number-min-max('Max retries:', model + '.maxRetries', '"expMaxRetries"', 'true', '10', '0', '29', 'Max number of times to retry')
+    .details-row
+        +number('Max interval:', model + '.maxSleepMs', '"expMaxSleepMs"', 'true', 'Integer.MAX_VALUE', '0', 'Max time in ms to sleep on each retry')

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/frontend/app/modules/states/configuration/clusters/general/discovery/zookeeper/retrypolicy/forever.jade
----------------------------------------------------------------------
diff --git a/modules/web-console/frontend/app/modules/states/configuration/clusters/general/discovery/zookeeper/retrypolicy/forever.jade b/modules/web-console/frontend/app/modules/states/configuration/clusters/general/discovery/zookeeper/retrypolicy/forever.jade
new file mode 100644
index 0000000..10e4fb1
--- /dev/null
+++ b/modules/web-console/frontend/app/modules/states/configuration/clusters/general/discovery/zookeeper/retrypolicy/forever.jade
@@ -0,0 +1,22 @@
+//-
+    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.jade
+
+-var model = 'backupItem.discovery.ZooKeeper.retryPolicy.Forever'
+
+.details-row
+    +number('Interval:', model + '.retryIntervalMs', '"feRetryIntervalMs"', 'true', '1000', '0', 'Time in ms between retry attempts')

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/frontend/app/modules/states/configuration/clusters/general/discovery/zookeeper/retrypolicy/n-times.jade
----------------------------------------------------------------------
diff --git a/modules/web-console/frontend/app/modules/states/configuration/clusters/general/discovery/zookeeper/retrypolicy/n-times.jade b/modules/web-console/frontend/app/modules/states/configuration/clusters/general/discovery/zookeeper/retrypolicy/n-times.jade
new file mode 100644
index 0000000..329f693
--- /dev/null
+++ b/modules/web-console/frontend/app/modules/states/configuration/clusters/general/discovery/zookeeper/retrypolicy/n-times.jade
@@ -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.
+
+include ../../../../../../../../../app/helpers/jade/mixins.jade
+
+-var model = 'backupItem.discovery.ZooKeeper.retryPolicy.NTimes'
+
+div
+    .details-row
+        +number('Retries:', model + '.n', '"n"', 'true', '10', '0', 'Number of times to retry')
+    .details-row
+        +number('Interval:', model + '.sleepMsBetweenRetries', '"ntSleepMsBetweenRetries"', 'true', '1000', '0', 'Time in ms between retry attempts')

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/frontend/app/modules/states/configuration/clusters/general/discovery/zookeeper/retrypolicy/one-time.jade
----------------------------------------------------------------------
diff --git a/modules/web-console/frontend/app/modules/states/configuration/clusters/general/discovery/zookeeper/retrypolicy/one-time.jade b/modules/web-console/frontend/app/modules/states/configuration/clusters/general/discovery/zookeeper/retrypolicy/one-time.jade
new file mode 100644
index 0000000..938ecea
--- /dev/null
+++ b/modules/web-console/frontend/app/modules/states/configuration/clusters/general/discovery/zookeeper/retrypolicy/one-time.jade
@@ -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.
+
+include ../../../../../../../../../app/helpers/jade/mixins.jade
+
+-var model = 'backupItem.discovery.ZooKeeper.retryPolicy.OneTime'
+
+div
+    .details-row
+        +number('Interval:', model + '.sleepMsBetweenRetry', '"oneSleepMsBetweenRetry"', 'true', '1000', '0', 'Time in ms to retry attempt')

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/frontend/app/modules/states/configuration/clusters/general/discovery/zookeeper/retrypolicy/until-elapsed.jade
----------------------------------------------------------------------
diff --git a/modules/web-console/frontend/app/modules/states/configuration/clusters/general/discovery/zookeeper/retrypolicy/until-elapsed.jade b/modules/web-console/frontend/app/modules/states/configuration/clusters/general/discovery/zookeeper/retrypolicy/until-elapsed.jade
new file mode 100644
index 0000000..513da6a
--- /dev/null
+++ b/modules/web-console/frontend/app/modules/states/configuration/clusters/general/discovery/zookeeper/retrypolicy/until-elapsed.jade
@@ -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.
+
+include ../../../../../../../../../app/helpers/jade/mixins.jade
+
+-var model = 'backupItem.discovery.ZooKeeper.retryPolicy.UntilElapsed'
+
+div
+    .details-row
+        +number('Total time:', model + '.maxElapsedTimeMs', '"ueMaxElapsedTimeMs"', 'true', '60000', '0', 'Total time in ms for execution of retry attempt')
+    .details-row
+        +number('Interval:', model + '.sleepMsBetweenRetries', '"ueSleepMsBetweenRetries"', 'true', '1000', '0', 'Time in ms between retry attempts')

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/frontend/app/modules/states/configuration/clusters/igfs.jade
----------------------------------------------------------------------
diff --git a/modules/web-console/frontend/app/modules/states/configuration/clusters/igfs.jade b/modules/web-console/frontend/app/modules/states/configuration/clusters/igfs.jade
new file mode 100644
index 0000000..181b44f
--- /dev/null
+++ b/modules/web-console/frontend/app/modules/states/configuration/clusters/igfs.jade
@@ -0,0 +1,37 @@
+//-
+    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.jade
+
+-var form = 'igfs'
+-var model = 'backupItem'
+
+.panel.panel-default(ng-form=form novalidate)
+    .panel-heading(bs-collapse-toggle ng-click='ui.loadPanel("#{form}")')
+        ignite-form-panel-chevron
+        label IGFS
+        ignite-form-field-tooltip.tipLabel
+            | IGFS (Ignite In-Memory File System) configurations assigned to cluster
+        ignite-form-revert
+    .panel-collapse(role='tabpanel' bs-collapse-target id=form)
+        .panel-body(ng-if='ui.isPanelLoaded("#{form}")')
+            .col-sm-6
+                .settings-row
+                    +dropdown-multiple('<span>IGFS:</span><a ui-sref="base.configuration.igfs({linkId: linkId()})"> (add)</a>',
+                        model + '.igfss', '"igfss"', true, 'Choose IGFS', 'No IGFS configured', 'igfss',
+                        'Select IGFS to start in cluster or add a new IGFS')
+            .col-sm-6
+                +preview-xml-java(model, 'igfss', 'igfss')


[41/52] ignite git commit: Web Console beta-3.

Posted by ak...@apache.org.
http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/backend/test/unit/IgfsService.test.js
----------------------------------------------------------------------
diff --git a/modules/web-console/backend/test/unit/IgfsService.test.js b/modules/web-console/backend/test/unit/IgfsService.test.js
new file mode 100644
index 0000000..3d78148
--- /dev/null
+++ b/modules/web-console/backend/test/unit/IgfsService.test.js
@@ -0,0 +1,190 @@
+/*
+ * 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 {assert} from 'chai';
+import injector from '../injector';
+import testIgfss from '../data/igfss.json';
+import testAccounts from '../data/accounts.json';
+
+let igfsService;
+let mongo;
+let errors;
+
+suite('IgfsServiceTestsSuite', () => {
+    const prepareUserSpaces = () => {
+        return mongo.Account.create(testAccounts)
+            .then((accounts) => {
+                return Promise.all(accounts.map((account) => mongo.Space.create(
+                    [
+                        {name: 'Personal space', owner: account._id, demo: false},
+                        {name: 'Demo space', owner: account._id, demo: true}
+                    ]
+                )))
+                    .then((spaces) => [accounts, spaces]);
+            });
+    };
+
+    suiteSetup(() => {
+        return Promise.all([injector('services/igfss'),
+            injector('mongo'),
+            injector('errors')])
+            .then(([_igfsService, _mongo, _errors]) => {
+                mongo = _mongo;
+                igfsService = _igfsService;
+                errors = _errors;
+            });
+    });
+
+    setup(() => {
+        return Promise.all([
+            mongo.Igfs.remove().exec(),
+            mongo.Account.remove().exec(),
+            mongo.Space.remove().exec()
+        ]);
+    });
+
+    test('Create new igfs', (done) => {
+        igfsService.merge(testIgfss[0])
+            .then((igfs) => {
+                assert.isNotNull(igfs._id);
+
+                return igfs._id;
+            })
+            .then((igfsId) => mongo.Igfs.findById(igfsId))
+            .then((igfs) => {
+                assert.isNotNull(igfs);
+            })
+            .then(done)
+            .catch(done);
+    });
+
+    test('Update existed igfs', (done) => {
+        const newName = 'NewUniqueName';
+
+        igfsService.merge(testIgfss[0])
+            .then((existIgfs) => {
+                const igfsBeforeMerge = {...testIgfss[0], _id: existIgfs._id, name: newName};
+
+                return igfsService.merge(igfsBeforeMerge);
+            })
+            .then((igfs) => mongo.Igfs.findById(igfs._id))
+            .then((igfsAfterMerge) => {
+                assert.equal(igfsAfterMerge.name, newName);
+            })
+            .then(done)
+            .catch(done);
+    });
+
+    test('Create duplicated igfs', (done) => {
+        igfsService.merge(testIgfss[0])
+            .then(() => igfsService.merge(testIgfss[0]))
+            .catch((err) => {
+                assert.instanceOf(err, errors.DuplicateKeyException);
+
+                done();
+            });
+    });
+
+    test('Remove existed igfs', (done) => {
+        igfsService.merge(testIgfss[0])
+            .then((existIgfs) => {
+                return mongo.Igfs.findById(existIgfs._id)
+                    .then((foundIgfs) => igfsService.remove(foundIgfs._id))
+                    .then(({rowsAffected}) => {
+                        assert.equal(rowsAffected, 1);
+                    })
+                    .then(() => mongo.Igfs.findById(existIgfs._id))
+                    .then((notFoundIgfs) => {
+                        assert.isNull(notFoundIgfs);
+                    });
+            })
+            .then(done)
+            .catch(done);
+    });
+
+    test('Remove igfs without identifier', (done) => {
+        igfsService.merge(testIgfss[0])
+            .then(() => igfsService.remove())
+            .catch((err) => {
+                assert.instanceOf(err, errors.IllegalArgumentException);
+
+                done();
+            });
+    });
+
+    test('Remove missed igfs', (done) => {
+        const validNoExistingId = 'FFFFFFFFFFFFFFFFFFFFFFFF';
+
+        igfsService.merge(testIgfss[0])
+            .then(() => igfsService.remove(validNoExistingId))
+            .then(({rowsAffected}) => {
+                assert.equal(rowsAffected, 0);
+            })
+            .then(done)
+            .catch(done);
+    });
+
+    test('Remove all igfss in space', (done) => {
+        prepareUserSpaces()
+            .then(([accounts, spaces]) => {
+                const currentUser = accounts[0];
+                const userIgfs = {...testIgfss[0], space: spaces[0][0]._id};
+
+                return igfsService.merge(userIgfs)
+                    .then(() => igfsService.removeAll(currentUser._id, false));
+            })
+            .then(({rowsAffected}) => {
+                assert.equal(rowsAffected, 1);
+            })
+            .then(done)
+            .catch(done);
+    });
+
+    test('Get all igfss by space', (done) => {
+        prepareUserSpaces()
+            .then(([accounts, spaces]) => {
+                const userIgfs = {...testIgfss[0], space: spaces[0][0]._id};
+
+                return igfsService.merge(userIgfs)
+                    .then((existIgfs) => {
+                        return igfsService.listBySpaces(spaces[0][0]._id)
+                            .then((igfss) => {
+                                assert.equal(igfss.length, 1);
+                                assert.equal(igfss[0]._id.toString(), existIgfs._id.toString());
+                            });
+                    });
+            })
+            .then(done)
+            .catch(done);
+    });
+
+    test('Update linked entities on update igfs', (done) => {
+        // TODO IGNITE-3262 Add test.
+        done();
+    });
+
+    test('Update linked entities on remove igfs', (done) => {
+        // TODO IGNITE-3262 Add test.
+        done();
+    });
+
+    test('Update linked entities on remove all igfss in space', (done) => {
+        // TODO IGNITE-3262 Add test.
+        done();
+    });
+});

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/docker/compose/backend/.dockerignore
----------------------------------------------------------------------
diff --git a/modules/web-console/docker/compose/backend/.dockerignore b/modules/web-console/docker/compose/backend/.dockerignore
new file mode 100644
index 0000000..6fadfa5
--- /dev/null
+++ b/modules/web-console/docker/compose/backend/.dockerignore
@@ -0,0 +1 @@
+build/node_modules

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/docker/compose/backend/Dockerfile
----------------------------------------------------------------------
diff --git a/modules/web-console/docker/compose/backend/Dockerfile b/modules/web-console/docker/compose/backend/Dockerfile
new file mode 100644
index 0000000..b4f7c9d
--- /dev/null
+++ b/modules/web-console/docker/compose/backend/Dockerfile
@@ -0,0 +1,30 @@
+#
+# 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.
+#
+
+FROM node:4
+
+RUN mkdir -p /opt/web-console-backend
+
+WORKDIR /opt/web-console-backend
+
+COPY build .
+
+RUN npm -g update npm && npm install --no-optional
+
+EXPOSE 3000 3001
+
+CMD ["npm", "start"]

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/docker/compose/backend/build.sh
----------------------------------------------------------------------
diff --git a/modules/web-console/docker/compose/backend/build.sh b/modules/web-console/docker/compose/backend/build.sh
new file mode 100644
index 0000000..f925bd7
--- /dev/null
+++ b/modules/web-console/docker/compose/backend/build.sh
@@ -0,0 +1,57 @@
+#!/bin/bash
+#
+# 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.
+#
+
+if [ -z "$IGNITE_HOME" ]; then
+    echo "Ignite source folder is not found or IGNITE_HOME environment variable is not valid."
+
+    exit 1
+fi
+
+WORK_DIR=`cd "$(dirname "$0")"; pwd`
+
+BUILD_DIR="$WORK_DIR/build"
+
+IGNITE_WEB_CONSOLE_BACKEND_DIR="$IGNITE_HOME/modules/web-console/backend"
+DOCKER_IMAGE_NAME="ignite/web-console-backend"
+
+echo "Receiving version..."
+VERSION=`cd $IGNITE_HOME && mvn org.apache.maven.plugins:maven-help-plugin:evaluate -Dexpression=project.version| grep -Ev '(^\[|Download\w+:)'`
+RELEASE_VERSION=${VERSION%-SNAPSHOT}
+
+echo "Building $DOCKER_IMAGE_NAME:$RELEASE_VERSION"
+echo "Step 1. Prepare build temp paths."
+cd $WORK_DIR
+rm -Rf $BUILD_DIR
+docker rmi -f $DOCKER_IMAGE_NAME:$RELEASE_VERSION
+
+echo "Step 2. Build ignite web agent."
+cd $IGNITE_HOME
+mvn versions:set -DnewVersion=$RELEASE_VERSION -DgenerateBackupPoms=false -Pweb-console -DartifactId='*'
+mvn clean package -pl :ignite-web-agent -am -P web-console -DskipTests=true
+mvn versions:set -DnewVersion=$VERSION -DgenerateBackupPoms=false -Pweb-console -DartifactId='*'
+
+echo "Step 3. Copy sources."
+cd $WORK_DIR
+cp -r $IGNITE_WEB_CONSOLE_BACKEND_DIR/. $BUILD_DIR
+cp $IGNITE_HOME/modules/web-console/web-agent/target/ignite-web-agent*.zip $BUILD_DIR/agent_dists/.
+
+echo "Step 4. Build docker image."
+docker build -f=./Dockerfile -t $DOCKER_IMAGE_NAME:$RELEASE_VERSION .
+
+echo "Step 5. Cleanup."
+rm -Rf $BUILD_DIR

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/docker/compose/docker-compose.yml
----------------------------------------------------------------------
diff --git a/modules/web-console/docker/compose/docker-compose.yml b/modules/web-console/docker/compose/docker-compose.yml
new file mode 100644
index 0000000..bacd769
--- /dev/null
+++ b/modules/web-console/docker/compose/docker-compose.yml
@@ -0,0 +1,59 @@
+#
+# 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.
+#
+
+mongodb:
+  image: mongo:latest
+  volumes:
+    # External volume for persisting data. (HOST_PATH:CONTAINER_PATH).
+    - ./data/mongo:/data/db
+
+backend:
+  image: ignite/web-console-backend:1.7.0
+  links:
+    # Link mongodb container as with mongodb hostname.
+    - mongodb:mongodb
+  ports:
+    # Proxy 3001 port from docker container to 3001 port host machine. (HOST_PORT:DOCKER_PORT)
+    - 3001:3001
+  # Restart on crash.
+  restart: always  
+  environment:
+    # Port for serving frontend API
+    - server_port=3000
+    # Cookie session secret
+    - server_sessionSecret="CHANGE ME"
+    # URL for mongodb connection
+    - mongodb_url=mongodb://mongodb/console
+    # Port for web-agent.
+    - agentServer_port=3001
+    # Mail connection settings. Leave empty if no needed. See also settings, https://github.com/nodemailer/nodemailer
+    - mail_service=""
+    - mail_sign=""
+    - mail_greeting=""
+    - mail_from=""
+    - mail_auth_user=""
+    - mail_auth_pass=""
+
+frontend:
+  image: ignite/web-console-frontend:1.7.0
+  links:
+    # Link backend container to proxy backend requests throught nginx container.
+    - backend:backend
+
+  ports:
+    # Proxy HTTP nginx port (HOST_PORT:DOCKER_PORT)
+    - 80:80

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/docker/compose/frontend/.dockerignore
----------------------------------------------------------------------
diff --git a/modules/web-console/docker/compose/frontend/.dockerignore b/modules/web-console/docker/compose/frontend/.dockerignore
new file mode 100644
index 0000000..caf0e8e
--- /dev/null
+++ b/modules/web-console/docker/compose/frontend/.dockerignore
@@ -0,0 +1,3 @@
+src/build
+src/ignite_modules_temp
+src/node_modules

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/docker/compose/frontend/Dockerfile
----------------------------------------------------------------------
diff --git a/modules/web-console/docker/compose/frontend/Dockerfile b/modules/web-console/docker/compose/frontend/Dockerfile
new file mode 100644
index 0000000..1b578d1
--- /dev/null
+++ b/modules/web-console/docker/compose/frontend/Dockerfile
@@ -0,0 +1,32 @@
+#
+# 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.
+#
+
+FROM nginx
+
+RUN mkdir -p /data/www
+
+WORKDIR /data/www
+
+COPY ./build .
+
+COPY nginx/nginx.conf /etc/nginx/nginx.conf
+COPY nginx/web-console.conf /etc/nginx/web-console.conf
+
+VOLUME /etc/nginx
+VOLUME /data/www
+
+EXPOSE 80

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/docker/compose/frontend/DockerfileBuild
----------------------------------------------------------------------
diff --git a/modules/web-console/docker/compose/frontend/DockerfileBuild b/modules/web-console/docker/compose/frontend/DockerfileBuild
new file mode 100644
index 0000000..277991f
--- /dev/null
+++ b/modules/web-console/docker/compose/frontend/DockerfileBuild
@@ -0,0 +1,30 @@
+#
+# 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.
+#
+
+FROM node:4
+
+RUN mkdir -p /opt/web-console-frontend
+
+WORKDIR /opt/web-console-frontend
+
+COPY src .
+
+RUN npm update -g npm && npm install --no-optional
+
+VOLUME /opt/web-console-frontend/build
+
+CMD ["npm", "run", "build"]

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/docker/compose/frontend/build.sh
----------------------------------------------------------------------
diff --git a/modules/web-console/docker/compose/frontend/build.sh b/modules/web-console/docker/compose/frontend/build.sh
new file mode 100644
index 0000000..4dfa57a
--- /dev/null
+++ b/modules/web-console/docker/compose/frontend/build.sh
@@ -0,0 +1,59 @@
+#!/bin/bash
+#
+# 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.
+#
+
+if [ -z "$IGNITE_HOME" ]; then
+    echo "Ignite source folder is not found or IGNITE_HOME environment variable is not valid."
+
+    exit 1
+fi
+
+WORK_DIR=`cd "$(dirname "$0")"; pwd`
+
+SOURCE_DIR=$WORK_DIR/src
+BUILD_DIR=$WORK_DIR/build
+
+DOCKER_BUILD_CONTAINER=web-console-frontend-builder
+DOCKER_BUILD_IMAGE_NAME=ignite/$DOCKER_BUILD_CONTAINER
+DOCKER_IMAGE_NAME=ignite/web-console-frontend
+
+echo "Receiving version..."
+VERSION=`cd $IGNITE_HOME && mvn org.apache.maven.plugins:maven-help-plugin:evaluate -Dexpression=project.version| grep -Ev '(^\[|Download\w+:)'`
+RELEASE_VERSION=${VERSION%-SNAPSHOT}
+
+echo "Building $DOCKER_IMAGE_NAME:$RELEASE_VERSION"
+echo "Step 1. Build frontend SPA"
+cd $WORK_DIR
+
+rm -Rf $SOURCE_DIR
+rm -Rf $BUILD_DIR
+mkdir -p $SOURCE_DIR
+mkdir -p $BUILD_DIR
+
+cp -r $IGNITE_HOME/modules/web-console/frontend/. $SOURCE_DIR
+
+docker build -f=./DockerfileBuild -t $DOCKER_BUILD_IMAGE_NAME:latest .
+docker run -it -v $BUILD_DIR:/opt/web-console-frontend/build --name $DOCKER_BUILD_CONTAINER $DOCKER_BUILD_IMAGE_NAME
+
+echo "Step 2. Build NGINX container with SPA and proxy configuration"
+docker build -f=./Dockerfile -t $DOCKER_IMAGE_NAME:$RELEASE_VERSION .
+
+echo "Step 3. Cleanup"
+docker rm -f $DOCKER_BUILD_CONTAINER
+docker rmi -f $DOCKER_BUILD_IMAGE_NAME
+rm -r $SOURCE_DIR
+rm -r $BUILD_DIR

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/docker/compose/frontend/nginx/nginx.conf
----------------------------------------------------------------------
diff --git a/modules/web-console/docker/compose/frontend/nginx/nginx.conf b/modules/web-console/docker/compose/frontend/nginx/nginx.conf
new file mode 100644
index 0000000..dc208f5
--- /dev/null
+++ b/modules/web-console/docker/compose/frontend/nginx/nginx.conf
@@ -0,0 +1,57 @@
+#
+# 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.
+#
+
+user  nginx;
+worker_processes  1;
+
+error_log  /var/log/nginx/error.log  warn;
+pid        /var/run/nginx.pid;
+
+events {
+  worker_connections  128;
+}
+
+http {
+  server_tokens off;
+  sendfile            on;
+  aio                 on;
+  tcp_nopush          on;
+
+  keepalive_timeout   60;
+  tcp_nodelay         on;
+
+  client_max_body_size 100m;
+
+  #access log
+  log_format main '$http_host $remote_addr - $remote_user [$time_local] '
+  '"$request" $status $bytes_sent '
+  '"$http_referer" "$http_user_agent" '
+  '"$gzip_ratio"';
+
+  include /etc/nginx/mime.types;
+  default_type  application/octet-stream;
+
+  gzip              on;
+  gzip_disable      "msie6";
+  gzip_types        text/plain text/css text/xml text/javascript application/json application/x-javascript application/xml application/xml+rss application/javascript;
+  gzip_vary         on;
+  gzip_comp_level   5;
+
+  access_log  /var/log/nginx/access.log  main;
+  #conf.d
+  include web-console.conf;
+}

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/docker/compose/frontend/nginx/web-console.conf
----------------------------------------------------------------------
diff --git a/modules/web-console/docker/compose/frontend/nginx/web-console.conf b/modules/web-console/docker/compose/frontend/nginx/web-console.conf
new file mode 100644
index 0000000..d80a7f9
--- /dev/null
+++ b/modules/web-console/docker/compose/frontend/nginx/web-console.conf
@@ -0,0 +1,59 @@
+#
+# 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.
+#
+
+upstream backend-api {
+  server backend:3000;
+}
+
+server {
+  listen 80;
+  server_name _;
+
+  set $ignite_console_dir /data/www;
+  set $maintenance $ignite_console_dir/maintenance.file;
+
+  root $ignite_console_dir;
+
+  error_page 500 502 503 504 /50x.html;
+
+  location / {
+    if (-f $maintenance) {
+      return 503;
+    }
+
+    try_files $uri /index.html = 404;
+  }
+
+  location /api/v1 {
+    rewrite /api/v1/(.*) /$1 break;
+    proxy_set_header Host $http_host;
+    proxy_pass http://backend-api;
+  }
+
+  location /socket.io {
+    proxy_set_header Upgrade $http_upgrade;
+    proxy_set_header Connection "upgrade";
+    proxy_http_version 1.1;
+    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
+    proxy_set_header Host $host;
+    proxy_pass http://backend-api;
+  }
+
+  location = /50x.html {
+    root $ignite_console_dir/error_page;
+  }
+}

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/docker/standalone/.dockerignore
----------------------------------------------------------------------
diff --git a/modules/web-console/docker/standalone/.dockerignore b/modules/web-console/docker/standalone/.dockerignore
new file mode 100644
index 0000000..35b7244
--- /dev/null
+++ b/modules/web-console/docker/standalone/.dockerignore
@@ -0,0 +1,2 @@
+build/frontend/node_modules
+build/backend/node_modules

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/docker/standalone/Dockerfile
----------------------------------------------------------------------
diff --git a/modules/web-console/docker/standalone/Dockerfile b/modules/web-console/docker/standalone/Dockerfile
new file mode 100644
index 0000000..785f109
--- /dev/null
+++ b/modules/web-console/docker/standalone/Dockerfile
@@ -0,0 +1,87 @@
+#
+# 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.
+#
+
+FROM ubuntu:14.04
+
+ENV NPM_CONFIG_LOGLEVEL info
+ENV NODE_VERSION 4.4.7
+
+# Before package list update.
+RUN set -ex  && \
+      for key in \
+        9554F04D7259F04124DE6B476D5A82AC7E37093B \
+        94AE36675C464D64BAFA68DD7434390BDBE9B9C5 \
+        0034A06D9D9B0064CE8ADF6BF1747F4AD2306D93 \
+        FD3A5288F042B6850C66B31F09FE44734EB7990E \
+        71DCFD284A79C3B38668286BC97EC7A07EDE3FC1 \
+        DD8F2338BAE7501E3DD5AC78C273792F7D83545D \
+        B9AE9905FFD7803F25714661B63B535A4C206CA9 \
+        C4F0DFFF4E8C1A8236409D08E73BC641CC11F4C8 \
+      ; do \
+        gpg --keyserver ha.pool.sks-keyservers.net --recv-keys "$key"; \
+      done
+
+RUN apt-key adv --keyserver hkp://keyserver.ubuntu.com:80 --recv EA312927 && \
+   echo "deb http://repo.mongodb.org/apt/ubuntu trusty/mongodb-org/3.2 multiverse" | sudo tee /etc/apt/sources.list.d/mongodb-org-3.2.list
+
+# Update package list & install.
+RUN apt-get update && \
+    apt-get install -y nginx-light mongodb-org-server curl xz-utils
+
+# Install Node JS.
+RUN curl -SLO "https://nodejs.org/dist/v$NODE_VERSION/node-v$NODE_VERSION-linux-x64.tar.xz"  && \
+  curl -SLO "https://nodejs.org/dist/v$NODE_VERSION/SHASUMS256.txt.asc" && \
+  gpg --batch --decrypt --output SHASUMS256.txt SHASUMS256.txt.asc && \
+  grep " node-v$NODE_VERSION-linux-x64.tar.xz\$" SHASUMS256.txt | sha256sum -c - && \
+  tar -xJf "node-v$NODE_VERSION-linux-x64.tar.xz" -C /usr/local --strip-components=1 && \
+  rm "node-v$NODE_VERSION-linux-x64.tar.xz" SHASUMS256.txt.asc SHASUMS256.txt
+
+# Install global node packages.
+RUN npm upgrade -g npm && npm install -g pm2
+
+# Install frontend & backend apps.
+RUN mkdir -p /opt/web-console
+
+# Copy source.
+WORKDIR /opt/web-console
+COPY build .
+
+# Install node modules.
+RUN cd /opt/web-console/frontend && npm install --no-optional && npm run build
+RUN cd /opt/web-console/backend && npm install --no-optional
+
+# Returns to base path.
+WORKDIR /opt/web-console
+
+# Copy nginx config.
+COPY ./nginx/nginx.conf /etc/nginx/nginx.conf
+COPY ./nginx/web-console.conf /etc/nginx/web-console.conf
+
+# Setup entrypoint.
+COPY ./entrypoint.sh .
+RUN chmod 755 /opt/web-console/entrypoint.sh
+
+# Clean up.
+RUN apt-get clean && rm -rf /var/lib/apt/lists/* /tmp/* /var/tmp/*
+
+VOLUME ["/etc/nginx"]
+VOLUME ["/var/lib/mongodb"]
+VOLUME ["/opt/web-console/serve/agent_dists"]
+
+EXPOSE 80 3001
+
+ENTRYPOINT ["/opt/web-console/entrypoint.sh"]

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/docker/standalone/build.sh
----------------------------------------------------------------------
diff --git a/modules/web-console/docker/standalone/build.sh b/modules/web-console/docker/standalone/build.sh
new file mode 100644
index 0000000..4365dec
--- /dev/null
+++ b/modules/web-console/docker/standalone/build.sh
@@ -0,0 +1,59 @@
+#!/bin/bash
+#
+# 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.
+#
+
+if [ -z "$IGNITE_HOME" ]; then
+    echo "Ignite source folder is not found or IGNITE_HOME environment variable is not valid."
+
+    exit 1
+fi
+
+WORK_DIR=`cd "$(dirname "$0")"; pwd`
+
+BUILD_DIR="$WORK_DIR/build"
+
+IGNITE_WEB_CONSOLE_DIR="$IGNITE_HOME/modules/web-console"
+DOCKER_IMAGE_NAME="ignite/web-console-standalone"
+
+echo "Receiving version..."
+VERSION=`cd $IGNITE_HOME && mvn org.apache.maven.plugins:maven-help-plugin:evaluate -Dexpression=project.version| grep -Ev '(^\[|Download\w+:)'`
+RELEASE_VERSION=${VERSION%-SNAPSHOT}
+
+echo "Building $DOCKER_IMAGE_NAME:$RELEASE_VERSION"
+echo "Step 1. Prepare build temp paths."
+cd $WORK_DIR
+rm -Rf $BUILD_DIR
+docker rmi -f $DOCKER_IMAGE_NAME:$RELEASE_VERSION
+mkdir -p $BUILD_DIR/frontend $BUILD_DIR/backend
+
+echo "Step 2. Build ignite web agent."
+cd $IGNITE_HOME
+mvn versions:set -DnewVersion=$RELEASE_VERSION -DgenerateBackupPoms=false -Pweb-console -DartifactId='*'
+mvn clean package -pl :ignite-web-agent -am -P web-console -DskipTests=true
+mvn versions:set -DnewVersion=$VERSION -DgenerateBackupPoms=false -Pweb-console -DartifactId='*'
+
+echo "Step 3. Copy sources."
+cd $WORK_DIR
+cp -r $IGNITE_WEB_CONSOLE_DIR/frontend/. $BUILD_DIR/frontend
+cp -r $IGNITE_WEB_CONSOLE_DIR/backend/. $BUILD_DIR/backend
+cp $IGNITE_HOME/modules/web-console/web-agent/target/ignite-web-agent*.zip $BUILD_DIR/backend/agent_dists/.
+
+echo "Step 4. Build docker image."
+docker build -f=./Dockerfile -t $DOCKER_IMAGE_NAME:$RELEASE_VERSION .
+
+echo "Step 5. Cleanup."
+rm -Rf $BUILD_DIR

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/docker/standalone/docker-compose.yml
----------------------------------------------------------------------
diff --git a/modules/web-console/docker/standalone/docker-compose.yml b/modules/web-console/docker/standalone/docker-compose.yml
new file mode 100644
index 0000000..561c88d
--- /dev/null
+++ b/modules/web-console/docker/standalone/docker-compose.yml
@@ -0,0 +1,41 @@
+#
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements.  See the NOTICE file distributed with
+# this work for additional information regarding copyright ownership.
+# The ASF licenses this file to You under the Apache License, Version 2.0
+# (the "License"); you may not use this file except in compliance with
+# the License.  You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+webconsole:
+  image: ignite/web-console-standalone
+  ports:
+    - 3080:80
+    - 3000:3000
+    - 3001:3001
+    - 27017:27017
+  restart: always
+  environment:
+    # Port for serving frontend API
+    - server_port=3000
+    # Cookie session secret
+    - server_sessionSecret="CHANGE ME"
+    # URL for mongodb connection
+    - mongodb_url=mongodb://127.0.0.1/console
+    # Port for web-agent.
+    - agentServer_port=3001
+    # Mail connection settings. Leave empty if no needed. See also settings, https://github.com/nodemailer/nodemailer
+    - mail_service=""
+    - mail_sign=""
+    - mail_greeting=""
+    - mail_from=""
+    - mail_auth_user=""
+    - mail_auth_pass=""

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/docker/standalone/entrypoint.sh
----------------------------------------------------------------------
diff --git a/modules/web-console/docker/standalone/entrypoint.sh b/modules/web-console/docker/standalone/entrypoint.sh
new file mode 100644
index 0000000..3882f06
--- /dev/null
+++ b/modules/web-console/docker/standalone/entrypoint.sh
@@ -0,0 +1,23 @@
+#!/bin/bash
+#
+# 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.
+#
+
+/usr/bin/mongod --fork --config=/etc/mongod.conf
+
+service nginx start
+
+cd backend && pm2 start ./index.js --no-daemon

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/docker/standalone/nginx/nginx.conf
----------------------------------------------------------------------
diff --git a/modules/web-console/docker/standalone/nginx/nginx.conf b/modules/web-console/docker/standalone/nginx/nginx.conf
new file mode 100644
index 0000000..dbc79d7
--- /dev/null
+++ b/modules/web-console/docker/standalone/nginx/nginx.conf
@@ -0,0 +1,55 @@
+#
+# 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.
+#
+
+user  www-data;
+worker_processes  1;
+
+error_log  /var/log/nginx/error.log  warn;
+pid        /var/run/nginx.pid;
+
+events {
+    worker_connections  128;
+}
+
+http {
+    server_tokens off;
+    sendfile            on;
+    tcp_nopush          on;
+
+    keepalive_timeout   60;
+    tcp_nodelay         on;
+
+    client_max_body_size 100m;
+
+    #access log
+    log_format main '$http_host $remote_addr - $remote_user [$time_local] '
+    '"$request" $status $bytes_sent '
+    '"$http_referer" "$http_user_agent" '
+    '"$gzip_ratio"';
+
+    include /etc/nginx/mime.types;
+    default_type  application/octet-stream;
+    gzip on;
+    gzip_disable "msie6";
+    gzip_types text/plain text/css text/xml text/javascript application/json application/x-javascript application/xml application/xml+rss application/javascript;
+    gzip_vary on;
+    gzip_comp_level 5;
+
+    access_log  /var/log/nginx/access.log  main;
+    #conf.d
+    include web-console.conf ;
+}

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/docker/standalone/nginx/web-console.conf
----------------------------------------------------------------------
diff --git a/modules/web-console/docker/standalone/nginx/web-console.conf b/modules/web-console/docker/standalone/nginx/web-console.conf
new file mode 100644
index 0000000..3de544f
--- /dev/null
+++ b/modules/web-console/docker/standalone/nginx/web-console.conf
@@ -0,0 +1,54 @@
+#
+# 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.
+#
+
+upstream backend-api {
+  server localhost:3000;
+}
+
+server {
+  listen 80;
+  server_name _;
+
+  set $ignite_console_dir /opt/web-console/frontend/build;
+
+  root $ignite_console_dir;
+
+  error_page 500 502 503 504 /50x.html;
+
+  location / {
+    try_files $uri /index.html = 404;
+  }
+
+  location /api/v1 {
+    rewrite /api/v1/(.*) /$1 break;
+    proxy_set_header Host $http_host;
+    proxy_pass http://backend-api;
+  }
+
+  location /socket.io {
+    proxy_set_header Upgrade $http_upgrade;
+    proxy_set_header Connection "upgrade";
+    proxy_http_version 1.1;
+    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
+    proxy_set_header Host $host;
+    proxy_pass http://backend-api;
+  }
+
+  location = /50x.html {
+    root $ignite_console_dir/error_page;
+  }
+}

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/frontend/.babelrc
----------------------------------------------------------------------
diff --git a/modules/web-console/frontend/.babelrc b/modules/web-console/frontend/.babelrc
new file mode 100644
index 0000000..a1d48c1
--- /dev/null
+++ b/modules/web-console/frontend/.babelrc
@@ -0,0 +1,9 @@
+{
+  "presets": ["angular"],
+  "plugins": [[
+    "transform-builtin-extend", {
+      "globals": ["Error", "Array"],
+      "approximate": true
+    }
+  ]]
+}

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/frontend/.eslintrc
----------------------------------------------------------------------
diff --git a/modules/web-console/frontend/.eslintrc b/modules/web-console/frontend/.eslintrc
new file mode 100644
index 0000000..a8a3bb8
--- /dev/null
+++ b/modules/web-console/frontend/.eslintrc
@@ -0,0 +1,202 @@
+parser: "babel-eslint"
+
+env:
+    es6: true
+    browser: true
+
+ecmaFeatures:
+    arrowFunctions: true
+    blockBindings: true
+    classes: true
+    defaultParams: true
+    destructuring: true
+    module: true
+    objectLiteralComputedProperties: true
+    objectLiteralShorthandMethods: true
+    objectLiteralShorthandProperties: true
+    spread: true
+    templateStrings: true
+    experimentalObjectRestSpread: true
+
+globals:
+    _: true
+    $: true
+    d3: true
+    io: true
+    window: true
+    global: true
+    angular: true
+    $generatorCommon: true
+    $generatorProperties: true
+    $generatorXml: true
+    $generatorJava: true
+    $generatorPom: true
+    $generatorReadme: true
+    $generatorDocker: true
+    $generatorOptional: true
+    saveAs: true
+    process: true
+
+rules:
+    arrow-parens: [1, "always"]
+    arrow-spacing: [1, { "before": true, "after": true }]
+    accessor-pairs: 2
+    block-scoped-var: 2
+    brace-style: [0, "1tbs"]
+    comma-dangle: [2, "never"]
+    comma-spacing: [2, {"before": false, "after": true}]
+    comma-style: [2, "last"]
+    complexity: [1, 40]
+    computed-property-spacing: [2, "never"]
+    consistent-return: 0
+    consistent-this: [0, "that"]
+    constructor-super: 2
+    curly: [2, "multi-or-nest"]
+    default-case: 2
+    dot-location: 0
+    dot-notation: [2, { "allowKeywords": true }]
+    eol-last: 2
+    eqeqeq: 2
+    func-names: 0
+    func-style: [0, "declaration"]
+    generator-star-spacing: 0
+    guard-for-in: 1
+    handle-callback-err: 0
+    id-length: [2, {"min": 1, "max": 60}]
+    indent: [2, 4, {"SwitchCase": 1}]
+    key-spacing: [2, { "beforeColon": false, "afterColon": true }]
+    lines-around-comment: 0
+    linebreak-style: [0, "unix"]
+    max-depth: [0, 4]
+    max-len: [0, 120, 4]
+    max-nested-callbacks: [1, 4]
+    max-params: [0, 3]
+    max-statements: [0, 10]
+    new-cap: 2
+    new-parens: 2
+    no-alert: 2
+    no-array-constructor: 2
+    no-bitwise: 0
+    no-caller: 2
+    no-catch-shadow: 2
+    no-cond-assign: 2
+    no-console: 0
+    no-constant-condition: 2
+    no-continue: 0
+    no-class-assign: 2
+    no-const-assign: 2
+    no-control-regex: 2
+    no-debugger: 2
+    no-delete-var: 2
+    no-div-regex: 0
+    no-dupe-keys: 2
+    no-dupe-args: 2
+    no-duplicate-case: 2
+    no-else-return: 2
+    no-empty: 2
+    no-empty-character-class: 2
+    no-eq-null: 2
+    no-eval: 2
+    no-ex-assign: 2
+    no-extend-native: 2
+    no-extra-bind: 2
+    no-extra-boolean-cast: 2
+    no-extra-parens: 0
+    no-extra-semi: 2
+    no-fallthrough: 2
+    no-floating-decimal: 1
+    no-func-assign: 2
+    no-implied-eval: 2
+    no-inline-comments: 0
+    no-inner-declarations: [2, "functions"]
+    no-invalid-regexp: 2
+    no-irregular-whitespace: 2
+    no-iterator: 2
+    no-label-var: 2
+    no-labels: 2
+    no-lone-blocks: 2
+    no-lonely-if: 2
+    no-implicit-coercion: [2, {"boolean": false, "number": true, "string": true}]
+    no-loop-func: 2
+    no-mixed-requires: [0, false]
+    no-mixed-spaces-and-tabs: [2, true]
+    no-multi-spaces: 2
+    no-multi-str: 2
+    no-multiple-empty-lines: [0, {"max": 2}]
+    no-native-reassign: 2
+    no-negated-in-lhs: 2
+    no-nested-ternary: 0
+    no-new: 2
+    no-new-func: 2
+    no-new-object: 2
+    no-new-require: 0
+    no-new-wrappers: 2
+    no-obj-calls: 2
+    no-octal: 2
+    no-octal-escape: 2
+    no-param-reassign: 0
+    no-path-concat: 0
+    no-plusplus: 0
+    no-process-env: 0
+    no-process-exit: 1
+    no-proto: 2
+    no-redeclare: 2
+    no-regex-spaces: 1
+    no-restricted-modules: 0
+    no-script-url: 0
+    no-self-compare: 2
+    no-sequences: 2
+    no-shadow: 2
+    no-shadow-restricted-names: 2
+    no-spaced-func: 2
+    no-sparse-arrays: 1
+    no-sync: 0
+    no-ternary: 0
+    no-trailing-spaces: 2
+    no-throw-literal: 0
+    no-this-before-super: 2
+    no-unexpected-multiline: 2
+    no-undef: 2
+    no-undef-init: 2
+    no-undefined: 2
+    no-unneeded-ternary: 2
+    no-unreachable: 2
+    no-unused-expressions: [2, { allowShortCircuit: true }]
+    no-unused-vars: [2, {"vars": "all", "args": "after-used"}]
+    no-use-before-define: 2
+    no-useless-call: 2
+    no-void: 0
+    no-var: 2
+    no-warning-comments: 0
+    no-with: 2
+    newline-after-var: 0
+    object-shorthand: [2, "always"]
+    one-var: [2, "never"]
+    operator-assignment: [2, "always"]
+    operator-linebreak: 0
+    padded-blocks: 0
+    prefer-const: 1
+    prefer-spread: 2
+    quote-props: [2, "as-needed"]
+    quotes: [2, "single"]
+    radix: 1
+    semi: [2, "always"]
+    semi-spacing: [2, {"before": false, "after": true}]
+    sort-vars: 0
+    keyword-spacing: 2
+    space-before-blocks: [2, "always"]
+    space-before-function-paren: [2, "never"]
+    space-in-parens: 0
+    space-infix-ops: 2
+    space-unary-ops: [2, { "words": true, "nonwords": false }]
+    spaced-comment: [1, "always"]
+    use-isnan: 2
+    valid-jsdoc: 0
+    valid-typeof: 2
+    vars-on-top: 2
+    wrap-iife: 0
+    wrap-regex: 0
+    yoda: [2, "never"]
+
+parserOptions:
+    sourceType: module

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/frontend/.gitignore
----------------------------------------------------------------------
diff --git a/modules/web-console/frontend/.gitignore b/modules/web-console/frontend/.gitignore
new file mode 100644
index 0000000..46bca13
--- /dev/null
+++ b/modules/web-console/frontend/.gitignore
@@ -0,0 +1,7 @@
+*.idea
+*.log
+.npmrc
+build/*
+node_modules
+ignite_modules_temp/*
+public/stylesheets/*.css

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/frontend/app/app.config.js
----------------------------------------------------------------------
diff --git a/modules/web-console/frontend/app/app.config.js b/modules/web-console/frontend/app/app.config.js
new file mode 100644
index 0000000..25c24b0
--- /dev/null
+++ b/modules/web-console/frontend/app/app.config.js
@@ -0,0 +1,86 @@
+/*
+ * 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 alertTemplateUrl from '../views/templates/alert.jade';
+
+const igniteConsoleCfg = angular.module('ignite-console.config', ['ngAnimate', 'mgcrea.ngStrap']);
+
+// Configure AngularJS animation: do not animate fa-spin.
+igniteConsoleCfg.config(['$animateProvider', ($animateProvider) => {
+    $animateProvider.classNameFilter(/^((?!(fa-spin)).)*$/);
+}]);
+
+// AngularStrap modal popup configuration.
+igniteConsoleCfg.config(['$modalProvider', ($modalProvider) => {
+    angular.extend($modalProvider.defaults, {
+        animation: 'am-fade-and-scale',
+        html: true
+    });
+}]);
+
+// AngularStrap popover configuration.
+igniteConsoleCfg.config(['$popoverProvider', ($popoverProvider) => {
+    angular.extend($popoverProvider.defaults, {
+        trigger: 'manual',
+        placement: 'right',
+        container: 'body',
+        templateUrl: '/templates/validation-error.html'
+    });
+}]);
+
+// AngularStrap tooltips configuration.
+igniteConsoleCfg.config(['$tooltipProvider', ($tooltipProvider) => {
+    angular.extend($tooltipProvider.defaults, {
+        container: 'body',
+        delay: 150,
+        placement: 'right',
+        html: 'true',
+        trigger: 'click hover'
+    });
+}]);
+
+// AngularStrap select (combobox) configuration.
+igniteConsoleCfg.config(['$selectProvider', ($selectProvider) => {
+    angular.extend($selectProvider.defaults, {
+        container: 'body',
+        maxLength: '5',
+        allText: 'Select All',
+        noneText: 'Clear All',
+        templateUrl: '/templates/select.html',
+        iconCheckmark: 'fa fa-check',
+        caretHtml: ''
+    });
+}]);
+
+// AngularStrap alerts configuration.
+igniteConsoleCfg.config(['$alertProvider', ($alertProvider) => {
+    angular.extend($alertProvider.defaults, {
+        container: 'body',
+        placement: 'top-right',
+        duration: '5',
+        templateUrl: alertTemplateUrl,
+        type: 'danger'
+    });
+}]);
+
+
+// AngularStrap dropdowns () configuration.
+igniteConsoleCfg.config(['$dropdownProvider', ($dropdownProvider) => {
+    angular.extend($dropdownProvider.defaults, {
+        templateUrl: 'templates/dropdown.html'
+    });
+}]);

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/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
new file mode 100644
index 0000000..45851a2
--- /dev/null
+++ b/modules/web-console/frontend/app/app.js
@@ -0,0 +1,270 @@
+/*
+ * 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 '../public/stylesheets/style.scss';
+import './helpers/jade/mixins.jade';
+
+import './app.config';
+
+import './decorator/select';
+import './decorator/tooltip';
+
+import './modules/form/form.module';
+import './modules/agent/agent.module.js';
+import './modules/sql/sql.module';
+import './modules/Demo/Demo.module.js';
+
+import './modules/states/signin.state';
+import './modules/states/logout.state';
+import './modules/states/password.state';
+import './modules/states/configuration.state';
+import './modules/states/profile.state';
+import './modules/states/admin.state';
+import './modules/states/errors.state';
+
+// ignite:modules
+import './modules/user/user.module';
+import './modules/branding/branding.module';
+import './modules/navbar/navbar.module';
+import './modules/configuration/configuration.module';
+import './modules/getting-started/GettingStarted.provider';
+import './modules/dialog/dialog.module';
+import './modules/version/Version.provider';
+import './modules/ace.module';
+import './modules/socket.module';
+import './modules/loading/loading.module';
+// endignite
+
+// Directives.
+import igniteAutoFocus from './directives/auto-focus.directive.js';
+import igniteBsAffixUpdate from './directives/bs-affix-update.directive';
+import igniteCentered from './directives/centered/centered.directive.js';
+import igniteCopyToClipboard from './directives/copy-to-clipboard.directive.js';
+import igniteHideOnStateChange from './directives/hide-on-state-change/hide-on-state-change.directive';
+import igniteInformation from './directives/information/information.directive';
+import igniteMatch from './directives/match.directive.js';
+import igniteOnClickFocus from './directives/on-click-focus.directive.js';
+import igniteOnEnter from './directives/on-enter.directive.js';
+import igniteOnEnterFocusMove from './directives/on-enter-focus-move.directive.js';
+import igniteOnEscape from './directives/on-escape.directive.js';
+import igniteUiAceDocker from './directives/ui-ace-docker/ui-ace-docker.directive';
+import igniteUiAceJava from './directives/ui-ace-java/ui-ace-java.directive';
+import igniteUiAcePojos from './directives/ui-ace-pojos/ui-ace-pojos.directive';
+import igniteUiAcePom from './directives/ui-ace-pom/ui-ace-pom.directive';
+import igniteUiAceTabs from './directives/ui-ace-tabs.directive';
+import igniteUiAceXml from './directives/ui-ace-xml/ui-ace-xml.directive';
+
+// Services.
+import ChartColors from './services/ChartColors.service';
+import Clone from './services/Clone.service.js';
+import Confirm from './services/Confirm.service.js';
+import ConfirmBatch from './services/ConfirmBatch.service.js';
+import CopyToClipboard from './services/CopyToClipboard.service';
+import Countries from './services/Countries.service';
+import Focus from './services/Focus.service';
+import InetAddress from './services/InetAddress.service';
+import JavaTypes from './services/JavaTypes.service';
+import Messages from './services/Messages.service';
+import ModelNormalizer from './services/ModelNormalizer.service.js';
+import LegacyTable from './services/LegacyTable.service';
+import ErrorPopover from './services/ErrorPopover.service';
+import FormUtils from './services/FormUtils.service';
+import LegacyUtils from './services/LegacyUtils.service';
+import UnsavedChangesGuard from './services/UnsavedChangesGuard.service';
+
+// Providers.
+
+// Filters.
+import byName from './filters/byName.filter';
+import domainsValidation from './filters/domainsValidation.filter';
+import hasPojo from './filters/hasPojo.filter';
+import duration from './filters/duration.filter';
+
+// Generators
+import $generatorCommon from 'generator/generator-common';
+import $generatorJava from 'generator/generator-java';
+import $generatorOptional from 'generator/generator-optional';
+import $generatorProperties from 'generator/generator-properties';
+import $generatorReadme from 'generator/generator-readme';
+import $generatorXml from 'generator/generator-xml';
+
+window.$generatorCommon = $generatorCommon;
+window.$generatorJava = $generatorJava;
+window.$generatorOptional = $generatorOptional;
+window.$generatorProperties = $generatorProperties;
+window.$generatorReadme = $generatorReadme;
+window.$generatorXml = $generatorXml;
+
+// Controllers
+import admin from 'controllers/admin-controller';
+import caches from 'controllers/caches-controller';
+import clusters from 'controllers/clusters-controller';
+import domains from 'controllers/domains-controller';
+import igfs from 'controllers/igfs-controller';
+import profile from 'controllers/profile-controller';
+import auth from './controllers/auth.controller';
+import resetPassword from './controllers/reset-password.controller';
+
+// Inject external modules.
+import 'ignite_modules_temp/index';
+
+import baseTemplate from '../views/base.jade';
+
+angular
+.module('ignite-console', [
+    // Optional AngularJS modules.
+    'ngAnimate',
+    'ngSanitize',
+    // Third party libs.
+    'ngRetina',
+    'btford.socket-io',
+    'mgcrea.ngStrap',
+    'ui.router',
+    'gridster',
+    'dndLists',
+    'nvd3',
+    'smart-table',
+    'treeControl',
+    'ui.grid',
+    'ui.grid.saveState',
+    'ui.grid.selection',
+    'ui.grid.resizeColumns',
+    'ui.grid.autoResize',
+    'ui.grid.exporter',
+    // Base modules.
+    'ignite-console.ace',
+    'ignite-console.Form',
+    'ignite-console.user',
+    'ignite-console.branding',
+    'ignite-console.socket',
+    'ignite-console.agent',
+    'ignite-console.sql',
+    'ignite-console.demo',
+    // States.
+    'ignite-console.states.login',
+    'ignite-console.states.logout',
+    'ignite-console.states.password',
+    'ignite-console.states.configuration',
+    'ignite-console.states.profile',
+    'ignite-console.states.admin',
+    'ignite-console.states.errors',
+    // Common modules.
+    'ignite-console.dialog',
+    'ignite-console.navbar',
+    'ignite-console.configuration',
+    'ignite-console.getting-started',
+    'ignite-console.version',
+    'ignite-console.loading',
+    // Ignite configuration module.
+    'ignite-console.config',
+    // Ignite modules.
+    'ignite-console.modules'
+])
+// Directives.
+.directive(...igniteAutoFocus)
+.directive(...igniteBsAffixUpdate)
+.directive(...igniteCentered)
+.directive(...igniteCopyToClipboard)
+.directive(...igniteHideOnStateChange)
+.directive(...igniteInformation)
+.directive(...igniteMatch)
+.directive(...igniteOnClickFocus)
+.directive(...igniteOnEnter)
+.directive(...igniteOnEnterFocusMove)
+.directive(...igniteOnEscape)
+.directive(...igniteUiAceDocker)
+.directive(...igniteUiAceJava)
+.directive(...igniteUiAcePojos)
+.directive(...igniteUiAcePom)
+.directive(...igniteUiAceTabs)
+.directive(...igniteUiAceXml)
+// Services.
+.service(...ChartColors)
+.service(...Clone)
+.service(...Confirm)
+.service(...ConfirmBatch)
+.service(...CopyToClipboard)
+.service(...Countries)
+.service(...Focus)
+.service(...InetAddress)
+.service(...JavaTypes)
+.service(...Messages)
+.service(...ModelNormalizer)
+.service(...LegacyTable)
+.service('IgniteErrorPopover', ErrorPopover)
+.service(...FormUtils)
+.service(...LegacyUtils)
+.service(...UnsavedChangesGuard)
+// Controllers.
+.controller(...admin)
+.controller(...auth)
+.controller(...resetPassword)
+.controller(...caches)
+.controller(...clusters)
+.controller(...domains)
+.controller(...igfs)
+.controller(...profile)
+// Filters.
+.filter(...hasPojo)
+.filter(...domainsValidation)
+.filter(...byName)
+.filter(...duration)
+.config(['$stateProvider', '$locationProvider', '$urlRouterProvider', ($stateProvider, $locationProvider, $urlRouterProvider) => {
+    // Set up the states.
+    $stateProvider
+        .state('base', {
+            url: '',
+            abstract: true,
+            templateUrl: baseTemplate
+        })
+        .state('settings', {
+            url: '/settings',
+            abstract: true,
+            templateUrl: baseTemplate
+        });
+
+    $urlRouterProvider.otherwise('/404');
+    $locationProvider.html5Mode(true);
+}])
+.run(['$rootScope', '$state', 'MetaTags', 'gettingStarted', ($root, $state, $meta, gettingStarted) => {
+    $root._ = _;
+    $root.$state = $state;
+    $root.$meta = $meta;
+    $root.gettingStarted = gettingStarted;
+}])
+.run(['$rootScope', 'IgniteAgentMonitor', ($root, agentMonitor) => {
+    $root.$on('user', () => agentMonitor.init());
+}])
+.run(['$rootScope', ($root) => {
+    $root.$on('$stateChangeStart', () => {
+        _.forEach(angular.element('.modal'), (m) => angular.element(m).scope().$hide());
+    });
+}])
+.run(['$rootScope', '$http', '$state', 'IgniteMessages', 'User',
+    ($root, $http, $state, Messages, User) => { // eslint-disable-line no-shadow
+        $root.revertIdentity = () => {
+            $http.get('/api/v1/admin/revert/identity')
+                .then(User.load)
+                .then((user) => {
+                    $root.$broadcast('user', user);
+
+                    $state.go('settings.admin');
+                })
+                .catch(Messages.showError);
+        };
+    }
+]);

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/frontend/app/controllers/auth.controller.js
----------------------------------------------------------------------
diff --git a/modules/web-console/frontend/app/controllers/auth.controller.js b/modules/web-console/frontend/app/controllers/auth.controller.js
new file mode 100644
index 0000000..21ffeb8
--- /dev/null
+++ b/modules/web-console/frontend/app/controllers/auth.controller.js
@@ -0,0 +1,30 @@
+/*
+ * 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.
+ */
+
+// Sign in controller.
+// TODO IGNITE-1936 Refactor this controller.
+export default ['auth', [
+    '$scope', 'IgniteFocus', 'IgniteCountries', 'Auth',
+    ($scope, Focus, Countries, Auth) => {
+        $scope.auth = Auth.auth;
+        $scope.forgotPassword = Auth.forgotPassword;
+        $scope.action = 'signin';
+        $scope.countries = Countries.getAll();
+
+        Focus.move('user_email');
+    }
+]];

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/frontend/app/controllers/reset-password.controller.js
----------------------------------------------------------------------
diff --git a/modules/web-console/frontend/app/controllers/reset-password.controller.js b/modules/web-console/frontend/app/controllers/reset-password.controller.js
new file mode 100644
index 0000000..da0c37b
--- /dev/null
+++ b/modules/web-console/frontend/app/controllers/reset-password.controller.js
@@ -0,0 +1,50 @@
+/*
+ * 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.
+ */
+
+// Controller for password reset.
+export default ['resetPassword', [
+    '$scope', '$modal', '$http', '$state', 'IgniteMessages', 'IgniteFocus',
+    ($scope, $modal, $http, $state, Messages, Focus) => {
+        if ($state.params.token) {
+            $http.post('/api/v1/password/validate/token', {token: $state.params.token})
+                .success((res) => {
+                    $scope.email = res.email;
+                    $scope.token = res.token;
+                    $scope.error = res.error;
+
+                    if ($scope.token && !$scope.error)
+                        Focus.move('user_password');
+                });
+        }
+
+        // Try to reset user password for provided token.
+        $scope.resetPassword = (reset_info) => {
+            $http.post('/api/v1/password/reset', reset_info)
+                .success(() => {
+                    $state.go('signin');
+
+                    Messages.showInfo('Password successfully changed');
+                })
+                .error((err, state) => {
+                    if (state === 503)
+                        $state.go('signin');
+
+                    Messages.showError(err);
+                });
+        };
+    }
+]];

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/frontend/app/data/colors.json
----------------------------------------------------------------------
diff --git a/modules/web-console/frontend/app/data/colors.json b/modules/web-console/frontend/app/data/colors.json
new file mode 100644
index 0000000..188e485
--- /dev/null
+++ b/modules/web-console/frontend/app/data/colors.json
@@ -0,0 +1,22 @@
+[
+  "#1f77b4",
+  "#ff7f0e",
+  "#2ca02c",
+  "#d62728",
+  "#9467bd",
+  "#8c564b",
+  "#e377c2",
+  "#7f7f7f",
+  "#bcbd22",
+  "#17becf",
+  "#ffbb78",
+  "#98df8a",
+  "#ff9896",
+  "#c5b0d5",
+  "#aec7e8",
+  "#c49c94",
+  "#f7b6d2",
+  "#c7c7c7",
+  "#dbdb8d",
+  "#9edae5"
+]

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/frontend/app/data/countries.json
----------------------------------------------------------------------
diff --git a/modules/web-console/frontend/app/data/countries.json b/modules/web-console/frontend/app/data/countries.json
new file mode 100644
index 0000000..f420f48
--- /dev/null
+++ b/modules/web-console/frontend/app/data/countries.json
@@ -0,0 +1,94 @@
+[
+  {
+    "name": "United States",
+    "code": "USA"
+  },
+  {
+    "name": "Canada",
+    "code": "CAN"
+  },
+  {
+    "name": "United Kingdom",
+    "code": "GBR"
+  },
+  {
+    "name": "Germany",
+    "code": "DEU"
+  },
+  {
+    "name": "France",
+    "code": "FRA"
+  },
+  {
+    "name": "Switzerland",
+    "code": "CHE"
+  },
+  {
+    "name": "Netherlands",
+    "code": "NLD"
+  },
+  {
+    "name": "Israel",
+    "code": "ISR"
+  },
+  {
+    "name": "Sweden",
+    "code": "SWE"
+  },
+  {
+    "name": "Russia",
+    "code": "RUS"
+  },
+  {
+    "name": "Other Europe",
+    "code": "Other Europe"
+  },
+  {
+    "name": "China",
+    "code": "CHN"
+  },
+  {
+    "name": "India",
+    "code": "IND"
+  },
+  {
+    "name": "Japan",
+    "code": "JPN"
+  },
+  {
+    "name": "Other Asia",
+    "code": "Other Asia"
+  },
+  {
+    "name": "Australia",
+    "code": "AUS"
+  },
+  {
+    "name": "Brazil",
+    "code": "BRA"
+  },
+  {
+    "name": "Argentina",
+    "code": "ARG"
+  },
+  {
+    "name": "Other South America",
+    "code": "Other South America"
+  },
+  {
+    "name": "South Africa",
+    "code": "ZAF"
+  },
+  {
+    "name": "Nigeria",
+    "code": "NGA"
+  },
+  {
+    "name": "Other Africa",
+    "code": "Other Africa"
+  },
+  {
+    "name": "Rest of the World",
+    "code": "Rest of the World"
+  }
+]

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/frontend/app/data/demo-info.json
----------------------------------------------------------------------
diff --git a/modules/web-console/frontend/app/data/demo-info.json b/modules/web-console/frontend/app/data/demo-info.json
new file mode 100644
index 0000000..0d2ad22
--- /dev/null
+++ b/modules/web-console/frontend/app/data/demo-info.json
@@ -0,0 +1,14 @@
+[
+    {
+        "title": "Apache Ignite Web Console Demo",
+        "message": [
+            "<div>",
+            " <h4><i class='fa fa-cogs fa-cursor-default'></i>&nbsp;What Can You Do</h4>",
+            " <ul>",
+            "  <li><b>Configuration</b> to checkout predefined clusters, caches, domain models and IGFS</li>",
+            "  <li><b>SQL</b> to run various SQL queries on the demo database</li>",
+            " </ul>",
+            "</div>"
+        ]
+    }
+]

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/frontend/app/data/event-types.json
----------------------------------------------------------------------
diff --git a/modules/web-console/frontend/app/data/event-types.json b/modules/web-console/frontend/app/data/event-types.json
new file mode 100644
index 0000000..8d0c878
--- /dev/null
+++ b/modules/web-console/frontend/app/data/event-types.json
@@ -0,0 +1,169 @@
+[
+  {
+    "label": "EVTS_CHECKPOINT",
+    "value": "EVTS_CHECKPOINT",
+    "class": "org.apache.ignite.events.EventType",
+    "events": [
+      "EVT_CHECKPOINT_SAVED",
+      "EVT_CHECKPOINT_LOADED",
+      "EVT_CHECKPOINT_REMOVED"
+    ]
+  },
+  {
+    "label": "EVTS_DEPLOYMENT",
+    "value": "EVTS_DEPLOYMENT",
+    "class": "org.apache.ignite.events.EventType",
+    "events": [
+      "EVT_CLASS_DEPLOYED",
+      "EVT_CLASS_UNDEPLOYED",
+      "EVT_CLASS_DEPLOY_FAILED",
+      "EVT_TASK_DEPLOYED",
+      "EVT_TASK_UNDEPLOYED",
+      "EVT_TASK_DEPLOY_FAILED"
+    ]
+  },
+  {
+    "label": "EVTS_ERROR",
+    "value": "EVTS_ERROR",
+    "class": "org.apache.ignite.events.EventType",
+    "events": [
+      "EVT_JOB_TIMEDOUT",
+      "EVT_JOB_FAILED",
+      "EVT_JOB_FAILED_OVER",
+      "EVT_JOB_REJECTED",
+      "EVT_JOB_CANCELLED",
+      "EVT_TASK_TIMEDOUT",
+      "EVT_TASK_FAILED",
+      "EVT_CLASS_DEPLOY_FAILED",
+      "EVT_TASK_DEPLOY_FAILED",
+      "EVT_TASK_DEPLOYED",
+      "EVT_TASK_UNDEPLOYED",
+      "EVT_CACHE_REBALANCE_STARTED",
+      "EVT_CACHE_REBALANCE_STOPPED"
+    ]
+  },
+  {
+    "label": "EVTS_DISCOVERY",
+    "value": "EVTS_DISCOVERY",
+    "class": "org.apache.ignite.events.EventType",
+    "events": [
+      "EVT_NODE_JOINED",
+      "EVT_NODE_LEFT",
+      "EVT_NODE_FAILED",
+      "EVT_NODE_SEGMENTED",
+      "EVT_CLIENT_NODE_DISCONNECTED",
+      "EVT_CLIENT_NODE_RECONNECTED"
+    ]
+  },
+  {
+    "label": "EVTS_JOB_EXECUTION",
+    "value": "EVTS_JOB_EXECUTION",
+    "class": "org.apache.ignite.events.EventType",
+    "events": [
+      "EVT_JOB_MAPPED",
+      "EVT_JOB_RESULTED",
+      "EVT_JOB_FAILED_OVER",
+      "EVT_JOB_STARTED",
+      "EVT_JOB_FINISHED",
+      "EVT_JOB_TIMEDOUT",
+      "EVT_JOB_REJECTED",
+      "EVT_JOB_FAILED",
+      "EVT_JOB_QUEUED",
+      "EVT_JOB_CANCELLED"
+    ]
+  },
+  {
+    "label": "EVTS_TASK_EXECUTION",
+    "value": "EVTS_TASK_EXECUTION",
+    "class": "org.apache.ignite.events.EventType",
+    "events": [
+      "EVT_TASK_STARTED",
+      "EVT_TASK_FINISHED",
+      "EVT_TASK_FAILED",
+      "EVT_TASK_TIMEDOUT",
+      "EVT_TASK_SESSION_ATTR_SET",
+      "EVT_TASK_REDUCED"
+    ]
+  },
+  {
+    "label": "EVTS_CACHE",
+    "value": "EVTS_CACHE",
+    "class": "org.apache.ignite.events.EventType",
+    "events": [
+      "EVT_CACHE_ENTRY_CREATED",
+      "EVT_CACHE_ENTRY_DESTROYED",
+      "EVT_CACHE_OBJECT_PUT",
+      "EVT_CACHE_OBJECT_READ",
+      "EVT_CACHE_OBJECT_REMOVED",
+      "EVT_CACHE_OBJECT_LOCKED",
+      "EVT_CACHE_OBJECT_UNLOCKED",
+      "EVT_CACHE_OBJECT_SWAPPED",
+      "EVT_CACHE_OBJECT_UNSWAPPED",
+      "EVT_CACHE_OBJECT_EXPIRED"
+    ]
+  },
+  {
+    "label": "EVTS_CACHE_REBALANCE",
+    "value": "EVTS_CACHE_REBALANCE",
+    "class": "org.apache.ignite.events.EventType",
+    "events": [
+      "EVT_CACHE_REBALANCE_STARTED",
+      "EVT_CACHE_REBALANCE_STOPPED",
+      "EVT_CACHE_REBALANCE_PART_LOADED",
+      "EVT_CACHE_REBALANCE_PART_UNLOADED",
+      "EVT_CACHE_REBALANCE_OBJECT_LOADED",
+      "EVT_CACHE_REBALANCE_OBJECT_UNLOADED",
+      "EVT_CACHE_REBALANCE_PART_DATA_LOST"
+    ]
+  },
+  {
+    "label": "EVTS_CACHE_LIFECYCLE",
+    "value": "EVTS_CACHE_LIFECYCLE",
+    "class": "org.apache.ignite.events.EventType",
+    "events": [
+      "EVT_CACHE_STARTED",
+      "EVT_CACHE_STOPPED",
+      "EVT_CACHE_NODES_LEFT"
+    ]
+  },
+  {
+    "label": "EVTS_CACHE_QUERY",
+    "value": "EVTS_CACHE_QUERY",
+    "class": "org.apache.ignite.events.EventType",
+    "events": [
+      "EVT_CACHE_QUERY_EXECUTED",
+      "EVT_CACHE_QUERY_OBJECT_READ"
+    ]
+  },
+  {
+    "label": "EVTS_SWAPSPACE",
+    "value": "EVTS_SWAPSPACE",
+    "class": "org.apache.ignite.events.EventType",
+    "events": [
+      "EVT_SWAP_SPACE_CLEARED",
+      "EVT_SWAP_SPACE_DATA_REMOVED",
+      "EVT_SWAP_SPACE_DATA_READ",
+      "EVT_SWAP_SPACE_DATA_STORED",
+      "EVT_SWAP_SPACE_DATA_EVICTED"
+    ]
+  },
+  {
+    "label": "EVTS_IGFS",
+    "value": "EVTS_IGFS",
+    "class": "org.apache.ignite.events.EventType",
+    "events": [
+      "EVT_IGFS_FILE_CREATED",
+      "EVT_IGFS_FILE_RENAMED",
+      "EVT_IGFS_FILE_DELETED",
+      "EVT_IGFS_FILE_OPENED_READ",
+      "EVT_IGFS_FILE_OPENED_WRITE",
+      "EVT_IGFS_FILE_CLOSED_WRITE",
+      "EVT_IGFS_FILE_CLOSED_READ",
+      "EVT_IGFS_FILE_PURGED",
+      "EVT_IGFS_META_UPDATED",
+      "EVT_IGFS_DIR_CREATED",
+      "EVT_IGFS_DIR_RENAMED",
+      "EVT_IGFS_DIR_DELETED"
+    ]
+  }
+]

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/frontend/app/data/getting-started.json
----------------------------------------------------------------------
diff --git a/modules/web-console/frontend/app/data/getting-started.json b/modules/web-console/frontend/app/data/getting-started.json
new file mode 100644
index 0000000..1b435ab
--- /dev/null
+++ b/modules/web-console/frontend/app/data/getting-started.json
@@ -0,0 +1,109 @@
+[
+    {
+        "title": "With Apache Ignite Web Console You Can",
+        "message": [
+            "<div class='col-xs-4'>",
+            " <img src='/images/ignite-puzzle.png' width='80%' class='getting-started-puzzle' />",
+            "</div>",
+            "<div class='col-xs-8'>",
+            " <ul>",
+            "  <li>Generate cluster configuration</li>",
+            "  <li>Import domain model from database</li>",
+            "  <li>Configure all needed caches</li>",
+            "  <li>Preview generated XML and Java code in browser</li>",
+            "  <li>Download ready-to-use Maven project</li>",
+            "  <li>Execute SQL queries on real clusters</li>",
+            " </ul>",
+            "</div>"
+        ]
+    },
+    {
+        "title": "Clusters",
+        "message": [
+            "<div class='col-xs-7'>",
+            " <img src='/images/cluster.png' width='100%' />",
+            "</div>",
+            "<div class='col-xs-5'>",
+            " <ul>",
+            "  <li>Configure cluster properties</li>",
+            "  <li>Associate cluster with caches</li>",
+            " </ul>",
+            "</div>"
+        ]
+    },
+    {
+        "title": "Domain Model",
+        "message": [
+            "<div class='col-xs-7'>",
+            " <img src='/images/domains.png' width='100%' />",
+            "</div>",
+            "<div class='col-xs-5'>",
+            " <ul>",
+            "  <li>Import database schemas</li>",
+            "  <li>Try in <span class='getting-started-demo'>Demo</span> mode</li>",
+            " </ul>",
+            "</div>"
+        ]
+    },
+    {
+        "title": "Caches",
+        "message": [
+            "<div class='col-xs-7'>",
+            " <img src='/images/cache.png' width='100%' />",
+            "</div>",
+            "<div class='col-xs-5'>",
+            " <ul>",
+            "  <li>Configure memory settings</li>",
+            "  <li>Configure persistence</li>",
+            " </ul>",
+            "</div>"
+        ]
+    },
+    {
+        "title": "In-memory File System",
+        "message": [
+            "<div class='col-xs-7'>",
+            " <img src='/images/igfs.png' width='100%' />",
+            "</div>",
+            "<div class='col-xs-5'>",
+            " <ul>",
+            "  <li>Configure IGFS properties</li>",
+            "  <li>Associate IGFS with clusters</li>",
+            " </ul>",
+            "</div>"
+        ]
+    },
+    {
+      "title": "Summary",
+      "message": [
+          "<div class='col-xs-7'>",
+          " <img src='/images/summary.png' width='100%' />",
+          "</div>",
+          "<div class='col-xs-5'>",
+          " <ul>",
+          "  <li>Preview XML configuration</li>",
+          "  <li>Preview code configuration</li>",
+          "  <li>Preview Docker file</li>",
+          "  <li>Preview POM dependencies</li>",
+          "  <li>Download ready-to-use project</li>",
+          " </ul>",
+          "</div>"
+      ]
+    },
+    {
+        "title": "SQL Queries",
+        "message": [
+            "<div class='col-xs-7'>",
+            " <img src='/images/query-table.png' width='100%' />",
+            "</div>",
+            "<div class='col-xs-5'>",
+            " <ul>",
+            "  <li>Execute SQL Queries</li>",
+            "  <li>View Execution Paln</li>",
+            "  <li>View In-Memory Schema</li>",
+            "  <li>View Streaming Charts</li>",
+            " </ul>",
+            "</div>"
+        ]
+    }
+]

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/frontend/app/data/java-classes.json
----------------------------------------------------------------------
diff --git a/modules/web-console/frontend/app/data/java-classes.json b/modules/web-console/frontend/app/data/java-classes.json
new file mode 100644
index 0000000..b0ec9fb
--- /dev/null
+++ b/modules/web-console/frontend/app/data/java-classes.json
@@ -0,0 +1,19 @@
+[
+  {"short": "BigDecimal", "full": "java.math.BigDecimal"},
+  {"short": "Boolean", "full": "java.lang.Boolean"},
+  {"short": "Byte", "full": "java.lang.Byte"},
+  {"short": "Character", "full": "java.lang.Character"},
+  {"short": "Date", "full": "java.sql.Date"},
+  {"short": "java.util.Date", "full": "java.util.Date"},
+  {"short": "Double", "full": "java.lang.Double"},
+  {"short": "Float", "full": "java.lang.Float"},
+  {"short": "Integer", "full": "java.lang.Integer"},
+  {"short": "Long", "full": "java.lang.Long"},
+  {"short": "Number", "full": "java.lang.Number"},
+  {"short": "Object", "full": "java.lang.Object"},
+  {"short": "Short", "full": "java.lang.Short"},
+  {"short": "String", "full": "java.lang.String"},
+  {"short": "Time", "full": "java.sql.Time"},
+  {"short": "Timestamp", "full": "java.sql.Timestamp"},
+  {"short": "UUID", "full": "java.util.UUID"}
+]

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/frontend/app/data/java-keywords.json
----------------------------------------------------------------------
diff --git a/modules/web-console/frontend/app/data/java-keywords.json b/modules/web-console/frontend/app/data/java-keywords.json
new file mode 100644
index 0000000..a2d5ec2
--- /dev/null
+++ b/modules/web-console/frontend/app/data/java-keywords.json
@@ -0,0 +1,55 @@
+[
+  "abstract",
+  "assert",
+  "boolean",
+  "break",
+  "byte",
+  "case",
+  "catch",
+  "char",
+  "class",
+  "const",
+  "continue",
+  "default",
+  "do",
+  "double",
+  "else",
+  "enum",
+  "extends",
+  "false",
+  "final",
+  "finally",
+  "float",
+  "for",
+  "goto",
+  "if",
+  "implements",
+  "import",
+  "instanceof",
+  "int",
+  "interface",
+  "long",
+  "native",
+  "new",
+  "null",
+  "package",
+  "private",
+  "protected",
+  "public",
+  "return",
+  "short",
+  "static",
+  "strictfp",
+  "super",
+  "switch",
+  "synchronized",
+  "this",
+  "throw",
+  "throws",
+  "transient",
+  "true",
+  "try",
+  "void",
+  "volatile",
+  "while"
+]

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/frontend/app/data/java-primitives.json
----------------------------------------------------------------------
diff --git a/modules/web-console/frontend/app/data/java-primitives.json b/modules/web-console/frontend/app/data/java-primitives.json
new file mode 100644
index 0000000..eab6b69
--- /dev/null
+++ b/modules/web-console/frontend/app/data/java-primitives.json
@@ -0,0 +1,9 @@
+[
+  "boolean",
+  "byte",
+  "double",
+  "float",
+  "int",
+  "long",
+  "short"
+]

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/frontend/app/data/pom-dependencies.json
----------------------------------------------------------------------
diff --git a/modules/web-console/frontend/app/data/pom-dependencies.json b/modules/web-console/frontend/app/data/pom-dependencies.json
new file mode 100644
index 0000000..7ab6c1b
--- /dev/null
+++ b/modules/web-console/frontend/app/data/pom-dependencies.json
@@ -0,0 +1,20 @@
+{
+    "Cloud": {"artifactId": "ignite-cloud"},
+    "S3": {"artifactId": "ignite-aws"},
+    "GoogleStorage": {"artifactId": "ignite-gce"},
+    "ZooKeeper": {"artifactId": "ignite-zookeeper"},
+
+    "Log4j": {"artifactId": "ignite-log4j"},
+    "Log4j2": {"artifactId": "ignite-log4j2"},
+    "JCL": {"artifactId": "ignite-jcl"},
+    "HadoopIgfsJcl": {"artifactId": "ignite-hadoop"},
+    "SLF4J": {"artifactId": "ignite-slf4j"},
+
+    "Generic": {"groupId": "com.mchange", "artifactId": "c3p0", "version": "0.9.5.1"},
+    "MySQL": {"groupId": "mysql", "artifactId": "mysql-connector-java", "version": "5.1.37"},
+    "PostgreSQL": {"groupId": "org.postgresql", "artifactId": "postgresql", "version": "9.4-1204-jdbc42"},
+    "H2": {"groupId": "com.h2database", "artifactId": "h2", "version": "1.3.175"},
+    "Oracle": {"groupId": "oracle", "artifactId": "jdbc", "version": "11.2", "jar": "ojdbc6.jar"},
+    "DB2": {"groupId": "ibm", "artifactId": "jdbc", "version": "4.19.26", "jar": "db2jcc4.jar"},
+    "SQLServer": {"groupId": "microsoft", "artifactId": "jdbc", "version": "4.1", "jar": "sqljdbc41.jar"}
+}

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/frontend/app/decorator/select.js
----------------------------------------------------------------------
diff --git a/modules/web-console/frontend/app/decorator/select.js b/modules/web-console/frontend/app/decorator/select.js
new file mode 100644
index 0000000..2d22707
--- /dev/null
+++ b/modules/web-console/frontend/app/decorator/select.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.
+ */
+
+import angular from 'angular';
+
+/**
+ * Special decorator that fix problem in AngularStrap selectAll / deselectAll methods.
+ * If this problem will be fixed in AngularStrap we can remove this delegate.
+ */
+angular.module('mgcrea.ngStrap.select')
+    .decorator('$select', ['$delegate', ($delegate) => {
+        function SelectFactoryDecorated(element, controller, config) {
+            const delegate = $delegate(element, controller, config);
+
+            // Common vars.
+            const options = angular.extend({}, $delegate.defaults, config);
+
+            const scope = delegate.$scope;
+
+            const valueByIndex = (index) => {
+                if (angular.isUndefined(scope.$matches[index]))
+                    return null;
+
+                return scope.$matches[index].value;
+            };
+
+            const selectAll = (active) => {
+                const selected = [];
+
+                scope.$apply(() => {
+                    for (let i = 0; i < scope.$matches.length; i++) {
+                        if (scope.$isActive(i) === active) {
+                            selected[i] = scope.$matches[i].value;
+
+                            delegate.activate(i);
+
+                            controller.$setViewValue(scope.$activeIndex.map(valueByIndex));
+                        }
+                    }
+                });
+
+                // Emit events.
+                for (let i = 0; i < selected.length; i++) {
+                    if (selected[i])
+                        scope.$emit(options.prefixEvent + '.select', selected[i], i, delegate);
+                }
+            };
+
+            scope.$selectAll = () => {
+                scope.$$postDigest(selectAll.bind(this, false));
+            };
+
+            scope.$selectNone = () => {
+                scope.$$postDigest(selectAll.bind(this, true));
+            };
+
+            return delegate;
+        }
+
+        SelectFactoryDecorated.defaults = $delegate.defaults;
+
+        return SelectFactoryDecorated;
+    }]);

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/frontend/app/decorator/tooltip.js
----------------------------------------------------------------------
diff --git a/modules/web-console/frontend/app/decorator/tooltip.js b/modules/web-console/frontend/app/decorator/tooltip.js
new file mode 100644
index 0000000..a47337a
--- /dev/null
+++ b/modules/web-console/frontend/app/decorator/tooltip.js
@@ -0,0 +1,56 @@
+/*
+ * 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';
+
+/**
+ * Special decorator that fix problem in AngularStrap $tooltip in special case.
+ * Case: when tooltip is shown on table row remove button and user click this button.
+ * If this problem will be fixed in AngularStrap we can remove this delegate.
+ */
+angular.module('mgcrea.ngStrap.tooltip')
+    .decorator('$tooltip', ['$delegate', ($delegate) => {
+        function TooltipFactoryDecorated(element, config) {
+            const delegate = $delegate(element, config);
+
+            const scope = delegate.$scope;
+
+            const options = delegate.$options;
+
+            const hideWraped = delegate.hide;
+
+            delegate.hide = (blur) => {
+                if (!delegate.$isShown)
+                    return;
+
+                if (delegate.$element !== null)
+                    return hideWraped(blur);
+
+                scope.$emit(options.prefixEvent + '.hide.before', delegate);
+
+                if (angular.isDefined(options.onBeforeHide) && angular.isFunction(options.onBeforeHide))
+                    options.onBeforeHide(delegate);
+
+                delegate.$isShown = scope.$isShown = false;
+                scope.$$phase || (scope.$root && scope.$root.$$phase) || scope.$digest();
+            };
+
+            return delegate;
+        }
+
+        return TooltipFactoryDecorated;
+    }]);

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/frontend/app/directives/auto-focus.directive.js
----------------------------------------------------------------------
diff --git a/modules/web-console/frontend/app/directives/auto-focus.directive.js b/modules/web-console/frontend/app/directives/auto-focus.directive.js
new file mode 100644
index 0000000..326fe1f
--- /dev/null
+++ b/modules/web-console/frontend/app/directives/auto-focus.directive.js
@@ -0,0 +1,26 @@
+/*
+ * 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.
+ */
+
+// Directive to auto-focus specified element.
+export default ['igniteAutoFocus', ['$timeout', ($timeout) => {
+    return {
+        restrict: 'AC',
+        link(scope, element) {
+            $timeout(() => element[0].focus());
+        }
+    };
+}]];


[25/52] ignite git commit: Web Console beta-3.

Posted by ak...@apache.org.
http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/frontend/gulpfile.babel.js/index.js
----------------------------------------------------------------------
diff --git a/modules/web-console/frontend/gulpfile.babel.js/index.js b/modules/web-console/frontend/gulpfile.babel.js/index.js
new file mode 100644
index 0000000..95602a1
--- /dev/null
+++ b/modules/web-console/frontend/gulpfile.babel.js/index.js
@@ -0,0 +1,26 @@
+/*
+ * 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 gulp from 'gulp';
+import requireDir from 'require-dir';
+
+// Require all tasks in gulpfile.js/tasks, including subfolders.
+requireDir('./tasks', { recurse: true });
+
+// Default no-arg task.
+gulp.task('default', ['build']);
+

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/frontend/gulpfile.babel.js/paths.js
----------------------------------------------------------------------
diff --git a/modules/web-console/frontend/gulpfile.babel.js/paths.js b/modules/web-console/frontend/gulpfile.babel.js/paths.js
new file mode 100644
index 0000000..9134e44
--- /dev/null
+++ b/modules/web-console/frontend/gulpfile.babel.js/paths.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.
+ */
+
+import path from 'path';
+
+const rootDir = path.resolve('./');
+const srcDir = path.resolve('app');
+const destDir = path.resolve('build');
+
+const igniteModulesDir = process.env.IGNITE_MODULES ? path.join(path.normalize(process.env.IGNITE_MODULES), 'frontend') : './ignite_modules';
+const igniteModulesTemp = path.resolve('ignite_modules_temp');
+
+const jadePaths = [
+    './views/*.jade',
+    './views/**/*.jade',
+    './app/helpers/**/*.jade',
+    './app/modules/states/configuration/**/*.jade',
+    './app/modules/sql/*.jade'
+];
+
+const resourcePaths = [
+    './public/**/*.png',
+    './public/*.ico'
+];
+
+const jadeModulePaths = [
+    igniteModulesDir + '/**/view/**/*.jade'
+];
+
+const appModulePaths = [
+    igniteModulesDir + '/index.js',
+    igniteModulesDir + '/**/main.js',
+    igniteModulesDir + '/**/module.js',
+    igniteModulesDir + '/**/app/modules/*.js',
+    igniteModulesDir + '/**/app/modules/**/*.js',
+    igniteModulesDir + '/**/app/modules/**/*.jade',
+    igniteModulesDir + '/**/app/**/*.css',
+    igniteModulesDir + '/**/app/**/*.scss',
+    igniteModulesDir + '/**/app/data/*.json'
+];
+
+const resourceModulePaths = [
+    igniteModulesDir + '/**/images/*.png',
+    igniteModulesDir + '/*.ico'
+];
+
+export {
+    rootDir,
+    srcDir,
+    destDir,
+    igniteModulesDir,
+    igniteModulesTemp,
+
+    jadePaths,
+    resourcePaths,
+
+    jadeModulePaths,
+    resourceModulePaths,
+    appModulePaths
+};

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/frontend/gulpfile.babel.js/tasks/build.js
----------------------------------------------------------------------
diff --git a/modules/web-console/frontend/gulpfile.babel.js/tasks/build.js b/modules/web-console/frontend/gulpfile.babel.js/tasks/build.js
new file mode 100644
index 0000000..7d7401b
--- /dev/null
+++ b/modules/web-console/frontend/gulpfile.babel.js/tasks/build.js
@@ -0,0 +1,21 @@
+/*
+ * 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 gulp from 'gulp';
+import sequence from 'gulp-sequence';
+
+gulp.task('build', (cb) => sequence(['clean', 'clean:ignite-modules-temp'], 'ignite:modules', ['copy:resource', 'jade'], 'bundle', cb));

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/frontend/gulpfile.babel.js/tasks/bundle.js
----------------------------------------------------------------------
diff --git a/modules/web-console/frontend/gulpfile.babel.js/tasks/bundle.js b/modules/web-console/frontend/gulpfile.babel.js/tasks/bundle.js
new file mode 100644
index 0000000..d3e8dca
--- /dev/null
+++ b/modules/web-console/frontend/gulpfile.babel.js/tasks/bundle.js
@@ -0,0 +1,32 @@
+/*
+ * 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 gulp from 'gulp';
+import webpack from 'webpack';
+import webpackConfig from '../webpack';
+import WebpackDevServer from 'webpack-dev-server';
+
+gulp.task('bundle', (cb) => {
+    if (process.env.NODE_ENV === 'development') {
+        // Important! Call webpack and WebpackDevServer must be inline.
+        new WebpackDevServer(webpack(webpackConfig), webpackConfig.devServer)
+            .listen(webpackConfig.devServer.port, 'localhost', cb);
+    }
+    else
+        webpack(webpackConfig, cb);
+});
+

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/frontend/gulpfile.babel.js/tasks/clean.js
----------------------------------------------------------------------
diff --git a/modules/web-console/frontend/gulpfile.babel.js/tasks/clean.js b/modules/web-console/frontend/gulpfile.babel.js/tasks/clean.js
new file mode 100644
index 0000000..c9104b2
--- /dev/null
+++ b/modules/web-console/frontend/gulpfile.babel.js/tasks/clean.js
@@ -0,0 +1,32 @@
+/*
+ * 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 gulp from 'gulp';
+import clean from 'gulp-rimraf';
+
+import { destDir, igniteModulesTemp } from '../paths';
+
+// Clean build folder, remove files.
+gulp.task('clean', () =>
+    gulp.src(`${destDir}/*`, {read: false})
+        .pipe(clean({ force: true }))
+);
+
+gulp.task('clean:ignite-modules-temp', () =>
+    gulp.src(igniteModulesTemp, {read: false})
+        .pipe(clean({ force: true }))
+);

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/frontend/gulpfile.babel.js/tasks/copy.js
----------------------------------------------------------------------
diff --git a/modules/web-console/frontend/gulpfile.babel.js/tasks/copy.js b/modules/web-console/frontend/gulpfile.babel.js/tasks/copy.js
new file mode 100644
index 0000000..59373a8
--- /dev/null
+++ b/modules/web-console/frontend/gulpfile.babel.js/tasks/copy.js
@@ -0,0 +1,33 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import gulp from 'gulp';
+import sequence from 'gulp-sequence';
+
+import { destDir, resourcePaths, resourceModulePaths } from '../paths';
+
+gulp.task('copy:resource', (cb) => sequence('copy:resource:app', 'copy:resource:ignite_modules', cb));
+
+gulp.task('copy:resource:app', () =>
+    gulp.src(resourcePaths)
+        .pipe(gulp.dest(destDir))
+);
+
+gulp.task('copy:resource:ignite_modules', () =>
+    gulp.src(resourceModulePaths)
+        .pipe(gulp.dest(`${destDir}/ignite_modules`))
+);

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/frontend/gulpfile.babel.js/tasks/ignite-modules.js
----------------------------------------------------------------------
diff --git a/modules/web-console/frontend/gulpfile.babel.js/tasks/ignite-modules.js b/modules/web-console/frontend/gulpfile.babel.js/tasks/ignite-modules.js
new file mode 100644
index 0000000..b97de7c
--- /dev/null
+++ b/modules/web-console/frontend/gulpfile.babel.js/tasks/ignite-modules.js
@@ -0,0 +1,55 @@
+/*
+ * 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 gulp from 'gulp';
+import inject from 'gulp-inject';
+import clean from 'gulp-rimraf';
+import sequence from 'gulp-sequence';
+import {appModulePaths, igniteModulesTemp} from '../paths';
+
+gulp.task('ignite:modules', (cb) => sequence('ignite:modules:copy', 'ignite:modules:inject', cb));
+
+gulp.task('ignite:modules:copy', () =>
+    gulp.src(appModulePaths)
+        .pipe(gulp.dest(igniteModulesTemp))
+);
+
+gulp.task('ignite:modules:inject', () =>
+    gulp.src(`${igniteModulesTemp}/index.js`)
+        .pipe(inject(gulp.src([`${igniteModulesTemp}/**/main.js`]), {
+            starttag: '/* ignite:modules */',
+            endtag: '/* endignite */',
+            transform: (filePath) => {
+                const igniteModuleName = filePath.replace(/.*ignite_modules_temp\/([^\/]+).*/mgi, '$1');
+
+                // Return file contents as string.
+                return `import './${igniteModuleName}/main';`;
+            }
+        }))
+        .pipe(inject(gulp.src([`${igniteModulesTemp}/**/main.js`]), {
+            starttag: '/* ignite-console:modules */',
+            endtag: '/* endignite */',
+            transform: (filePath, file, i) => {
+                const igniteModuleName = filePath.replace(/.*ignite_modules_temp\/([^\/]+).*/mgi, '$1');
+
+                // Return file contents as string.
+                return (i ? ',' : '') + `'ignite-console.${igniteModuleName}'`;
+            }
+        }))
+        .pipe(clean({force: true}))
+        .pipe(gulp.dest(igniteModulesTemp))
+);

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/frontend/gulpfile.babel.js/tasks/jade.js
----------------------------------------------------------------------
diff --git a/modules/web-console/frontend/gulpfile.babel.js/tasks/jade.js b/modules/web-console/frontend/gulpfile.babel.js/tasks/jade.js
new file mode 100644
index 0000000..b150373
--- /dev/null
+++ b/modules/web-console/frontend/gulpfile.babel.js/tasks/jade.js
@@ -0,0 +1,40 @@
+/*
+ * 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 gulp from 'gulp';
+import jade from 'gulp-jade';
+import sequence from 'gulp-sequence';
+
+import { jadePaths, jadeModulePaths, destDir } from '../paths';
+
+const jadeOptions = {
+    basedir: './'
+};
+
+gulp.task('jade', (cb) => sequence('jade:source', 'jade:ignite_modules', cb));
+
+gulp.task('jade:source', () =>
+    gulp.src(jadePaths)
+        .pipe(jade(jadeOptions))
+        .pipe(gulp.dest(destDir))
+);
+
+gulp.task('jade:ignite_modules', () =>
+    gulp.src(jadeModulePaths)
+        .pipe(jade(jadeOptions))
+        .pipe(gulp.dest(`${destDir}/ignite_modules`))
+);

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/frontend/gulpfile.babel.js/tasks/test.js
----------------------------------------------------------------------
diff --git a/modules/web-console/frontend/gulpfile.babel.js/tasks/test.js b/modules/web-console/frontend/gulpfile.babel.js/tasks/test.js
new file mode 100644
index 0000000..ad4108d
--- /dev/null
+++ b/modules/web-console/frontend/gulpfile.babel.js/tasks/test.js
@@ -0,0 +1,92 @@
+/*
+ * 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 gulp from 'gulp';
+import karmaBabelPreprocessor from 'karma-babel-preprocessor';
+import karmaPhantomjsLauncher from 'karma-phantomjs-launcher';
+import karmaWebpack from 'karma-webpack';
+import karmaJasmine from 'karma-jasmine';
+
+import {Server} from 'karma';
+
+import {rootDir} from '../paths';
+
+gulp.task('test', (cb) => {
+    new Server({
+        // Base path that will be used to resolve all patterns (eg. files, exclude).
+        basePath: rootDir,
+
+        // Frameworks to use available frameworks: https://npmjs.org/browse/keyword/karma-adapter
+        frameworks: ['jasmine'],
+
+        // List of files / patterns to load in the browser.
+        files: [
+            'test/**/*.test.js'
+        ],
+
+        plugins: [
+            karmaBabelPreprocessor,
+            karmaPhantomjsLauncher,
+            karmaWebpack,
+            karmaJasmine
+        ],
+
+        // Preprocess matching files before serving them to the browser
+        // available preprocessors: https://npmjs.org/browse/keyword/karma-preprocessor.
+        preprocessors: {
+            'test/**/*.js': ['webpack']
+        },
+
+        webpack: {
+            devtool: 'inline-source-map',
+            module: {
+                loaders: [
+                    {test: /\.js/, loaders: ['babel'], exclude: /node_modules/}
+                ]
+            },
+            resolve: {
+                extensions: ['', '.js']
+            }
+        },
+
+        // Test results reporter to use
+        // possible values: 'dots', 'progress'
+        // available reporters: https://npmjs.org/browse/keyword/karma-reporter.
+        reporters: ['progress'],
+
+        // web server port
+        port: 9876,
+
+        // enable / disable colors in the output (reporters and logs)
+        colors: true,
+
+        // enable / disable watching file and executing tests whenever any file changes
+        autoWatch: true,
+
+        // start these browsers
+        // available browser launchers: https://npmjs.org/browse/keyword/karma-launcher
+        browsers: ['PhantomJS'],
+
+        // Continuous Integration mode
+        // if true, Karma captures browsers, runs the tests and exits
+        singleRun: true,
+
+        // Concurrency level
+        // how many browser should be started simultaneous
+        concurrency: Infinity
+    }, cb).start();
+});

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/frontend/gulpfile.babel.js/tasks/watch.js
----------------------------------------------------------------------
diff --git a/modules/web-console/frontend/gulpfile.babel.js/tasks/watch.js b/modules/web-console/frontend/gulpfile.babel.js/tasks/watch.js
new file mode 100644
index 0000000..c179f9c
--- /dev/null
+++ b/modules/web-console/frontend/gulpfile.babel.js/tasks/watch.js
@@ -0,0 +1,31 @@
+/*
+ * 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 gulp from 'gulp';
+import sequence from 'gulp-sequence';
+
+import { jadePaths, jadeModulePaths, resourcePaths, resourceModulePaths, appModulePaths } from '../paths';
+
+gulp.task('watch:ignite-modules', (cb) => sequence('clean:ignite-modules-temp', 'ignite:modules', cb));
+
+// Build + watch task.
+gulp.task('watch', ['build'], () => {
+    gulp.watch(jadePaths.concat(jadeModulePaths), ['jade']);
+    gulp.watch(resourcePaths, ['copy:resource:app']);
+    gulp.watch(resourceModulePaths, ['copy:resource:ignite_modules']);
+    gulp.watch(appModulePaths, ['watch:ignite-modules']);
+});

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/frontend/gulpfile.babel.js/webpack/common.js
----------------------------------------------------------------------
diff --git a/modules/web-console/frontend/gulpfile.babel.js/webpack/common.js b/modules/web-console/frontend/gulpfile.babel.js/webpack/common.js
new file mode 100644
index 0000000..e3d88b3
--- /dev/null
+++ b/modules/web-console/frontend/gulpfile.babel.js/webpack/common.js
@@ -0,0 +1,189 @@
+/*
+ * 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 path from 'path';
+import fs from 'fs';
+import webpack from 'webpack';
+import autoprefixer from 'autoprefixer-core';
+import jade from 'jade';
+import progressPlugin from './plugins/progress';
+import eslintFormatter from 'eslint-friendly-formatter';
+
+import ExtractTextPlugin from 'extract-text-webpack-plugin';
+import HtmlWebpackPlugin from 'html-webpack-plugin';
+
+import {srcDir, destDir, rootDir, igniteModulesDir} from '../paths';
+
+const NODE_ENV = process.env.NODE_ENV || 'production';
+const development = NODE_ENV === 'development';
+const node_modules_path = path.resolve('node_modules');
+const cssLoader = 'css-loader?sourceMap!postcss-loader';
+const stylesLoader = cssLoader + '!sass-loader?outputStyle=expanded&sourceMap=true&sourceMapContents=true';
+
+let favicon = 'build/ignite_modules/favicon.ico';
+
+try {
+    fs.accessSync(path.join(igniteModulesDir, 'favicon.ico'), fs.F_OK);
+} catch (ignore) {
+    favicon = 'build/favicon.ico';
+}
+
+export default () => {
+    const assetsLoader = development ? 'url-loader' : 'file-loader';
+
+    return {
+        cache: true,
+        node: {
+            fs: 'empty'
+        },
+
+        // Entry points.
+        entry: {
+            polyfill: 'babel-polyfill',
+            app: path.join(srcDir, 'app.js'),
+            vendor: path.join(srcDir, 'vendor.js')
+        },
+
+        // Output system.
+        output: {
+            path: destDir,
+            publicPath: './',
+            filename: '[name].js'
+        },
+
+        // Resolves modules.
+        resolve: {
+            extensions: [
+                '',
+                '.js'
+            ],
+            root: [rootDir],
+            modulesDirectories: [
+                node_modules_path,
+                './'
+            ]
+        },
+
+        // Modules resolvers.
+        /* global require */
+        module: {
+            noParse: [],
+            preLoaders: [
+                {
+                    test: /\.js$/,
+                    exclude: [node_modules_path],
+                    loader: 'eslint-loader'
+                }
+            ],
+            loaders: [
+                {
+                    test: /\.json$/,
+                    loader: 'json-loader'
+                },
+                {
+                    test: /\.jade$/,
+                    loaders: [
+                        `ngtemplate-loader?relativeTo=${rootDir}`,
+                        'html-loader?attrs[]=img:src&attrs[]=img:data-src',
+                        'jade-html-loader'
+                    ]
+                },
+                {
+                    test: /\.js$/,
+                    exclude: [node_modules_path],
+                    loader: 'babel-loader',
+                    query: {
+                        cacheDirectory: true,
+                        plugins: ['transform-runtime',
+                            'add-module-exports'],
+                        presets: ['angular']
+
+                    }
+                },
+                {
+                    test: /\.css$/,
+                    loader: development ? `style-loader!${cssLoader}` : ExtractTextPlugin.extract('style-loader', cssLoader)
+                },
+                {
+                    test: /\.(scss|sass)$/,
+                    loader: development ? `style-loader!${stylesLoader}` : ExtractTextPlugin.extract('style-loader', stylesLoader)
+                },
+                {
+                    test: /\.(woff2|woff|ttf|eot|svg)?(\?v=[0-9]\.[0-9]\.[0-9])?$/,
+                    loaders: [
+                        `${assetsLoader}?name=assets/fonts/[name].[ext]`
+                    ]
+                },
+                {
+                    test: /\.(jpe?g|png|gif)$/i,
+                    loaders: [`${assetsLoader}?name=assets/images/[name]_[hash].[ext]`]
+                },
+                {
+                    test: require.resolve('jquery'),
+                    loaders: [
+                        'expose-loader?$',
+                        'expose-loader?jQuery'
+                    ]
+                },
+                {
+                    test: require.resolve('nvd3'),
+                    loaders: [
+                        'expose-loader?nv'
+                    ]
+                }
+            ]
+        },
+
+        // Postcss configuration.
+        postcss: [autoprefixer({browsers: ['last 2 versions']})],
+
+        // ESLint loader configuration.
+        eslint: {
+            failOnWarning: false,
+            failOnError: false,
+            formatter: eslintFormatter
+        },
+
+        // Load plugins.
+        plugins: [
+            new webpack.ProvidePlugin({
+                $: 'jquery',
+                jQuery: 'jquery',
+                _: 'lodash',
+                nv: 'nvd3'
+            }),
+            new webpack.DefinePlugin({NODE_ENV: JSON.stringify(NODE_ENV)}),
+            // new webpack.NoErrorsPlugin(),
+            new webpack.optimize.DedupePlugin(),
+            new webpack.optimize.CommonsChunkPlugin({
+                name: 'common',
+                chunks: ['vendor', 'app']
+            }),
+            new webpack.optimize.AggressiveMergingPlugin({moveToParents: true}),
+            new webpack.optimize.OccurenceOrderPlugin(),
+            new ExtractTextPlugin('assets/css/[name]' + (development ? '' : '.[chunkhash]') + '.css', {allChunks: true}),
+            new HtmlWebpackPlugin({
+                filename: 'index.html',
+                templateContent: () => {
+                    return jade.renderFile(path.join(rootDir, 'views', 'index.jade'));
+                },
+                favicon
+            }),
+            progressPlugin
+        ]
+    };
+};

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/frontend/gulpfile.babel.js/webpack/environments/development.js
----------------------------------------------------------------------
diff --git a/modules/web-console/frontend/gulpfile.babel.js/webpack/environments/development.js b/modules/web-console/frontend/gulpfile.babel.js/webpack/environments/development.js
new file mode 100644
index 0000000..229760e
--- /dev/null
+++ b/modules/web-console/frontend/gulpfile.babel.js/webpack/environments/development.js
@@ -0,0 +1,69 @@
+/*
+ * 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 path from 'path';
+import webpack from 'webpack';
+
+import {destDir, rootDir, srcDir} from '../../paths';
+
+export default () => {
+    const plugins = [
+        new webpack.HotModuleReplacementPlugin()
+    ];
+
+    return {
+        entry: {
+            webpack: 'webpack-dev-server/client?http://localhost:9000/',
+            app: [path.join(srcDir, 'app.js'), 'webpack/hot/only-dev-server']
+        },
+        context: rootDir,
+        debug: true,
+        devtool: 'source-map',
+        watch: true,
+        devServer: {
+            compress: true,
+            historyApiFallback: true,
+            publicPath: '/',
+            contentBase: destDir,
+            info: true,
+            hot: true,
+            inline: true,
+            proxy: {
+                '/socket.io': {
+                    target: 'http://localhost:3000',
+                    changeOrigin: true,
+                    ws: true
+                },
+                '/api/v1/*': {
+                    target: 'http://localhost:3000',
+                    changeOrigin: true,
+                    pathRewrite: {
+                        '^/api/v1': ''
+                    }
+                }
+            },
+            watchOptions: {
+                aggregateTimeout: 1000,
+                poll: 2000
+            },
+            stats: {colors: true},
+            port: 9000
+        },
+        stats: {colors: true},
+        plugins
+    };
+};

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/frontend/gulpfile.babel.js/webpack/environments/production.js
----------------------------------------------------------------------
diff --git a/modules/web-console/frontend/gulpfile.babel.js/webpack/environments/production.js b/modules/web-console/frontend/gulpfile.babel.js/webpack/environments/production.js
new file mode 100644
index 0000000..db66720
--- /dev/null
+++ b/modules/web-console/frontend/gulpfile.babel.js/webpack/environments/production.js
@@ -0,0 +1,45 @@
+/*
+ * 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 webpack from 'webpack';
+
+import {destDir, rootDir} from '../../paths';
+
+export default () => {
+    const plugins = [
+        new webpack.optimize.UglifyJsPlugin({
+            path: destDir,
+            minimize: true,
+            warnings: false,
+            sourceMap: false,
+            mangle: true
+        })
+    ];
+
+    return {
+        context: rootDir,
+        bail: true, // Cancel build on error.
+        debug: false,
+        devtool: 'cheap-source-map',
+        output: {
+            publicPath: '/',
+            filename: '[name].[chunkhash].js',
+            path: destDir
+        },
+        plugins
+    };
+};

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/frontend/gulpfile.babel.js/webpack/index.js
----------------------------------------------------------------------
diff --git a/modules/web-console/frontend/gulpfile.babel.js/webpack/index.js b/modules/web-console/frontend/gulpfile.babel.js/webpack/index.js
new file mode 100644
index 0000000..6682f9c
--- /dev/null
+++ b/modules/web-console/frontend/gulpfile.babel.js/webpack/index.js
@@ -0,0 +1,32 @@
+/*
+ * 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 _ from 'lodash';
+import commonConfig from './common';
+import devConfig from './environments/development';
+import prodConfig from './environments/production';
+
+const env = process.env.NODE_ENV || 'production';
+
+// Config by environments.
+const configs = {
+    production: prodConfig,
+    development: devConfig
+};
+
+// Load config file by environment
+export default _.merge(commonConfig(), configs[env]());

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/frontend/gulpfile.babel.js/webpack/plugins/progress.js
----------------------------------------------------------------------
diff --git a/modules/web-console/frontend/gulpfile.babel.js/webpack/plugins/progress.js b/modules/web-console/frontend/gulpfile.babel.js/webpack/plugins/progress.js
new file mode 100644
index 0000000..5f753c7
--- /dev/null
+++ b/modules/web-console/frontend/gulpfile.babel.js/webpack/plugins/progress.js
@@ -0,0 +1,82 @@
+/*
+ * 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 ProgressPlugin from 'webpack/lib/ProgressPlugin';
+
+let chars = 0;
+let lastState = 0;
+let lastStateTime = 0;
+
+const outputStream = process.stdout;
+
+const _goToLineStart = (nextMessage) => {
+    let str = '';
+
+    for (; chars > nextMessage.length; chars--)
+        str += '\b \b';
+
+    chars = nextMessage.length;
+
+    for (let i = 0; i < chars; i++)
+        str += '\b';
+
+    if (str)
+        outputStream.write(str);
+};
+
+export default new ProgressPlugin((percentage, msg) => {
+    let state = msg;
+
+    if (percentage < 1) {
+        percentage = Math.floor(percentage * 100);
+
+        msg = percentage + '% ' + msg;
+
+        if (percentage < 100)
+            msg = ' ' + msg;
+
+        if (percentage < 10)
+            msg = ' ' + msg;
+    }
+
+    state = state.replace(/^\d+\/\d+\s+/, '');
+
+    if (percentage === 0) {
+        lastState = null;
+        lastStateTime = (new Date()).getTime();
+    }
+    else if (state !== lastState || percentage === 1) {
+        const now = (new Date()).getTime();
+
+        if (lastState) {
+            const stateMsg = (now - lastStateTime) + 'ms ' + lastState;
+
+            _goToLineStart(stateMsg);
+
+            outputStream.write(stateMsg + '\n');
+
+            chars = 0;
+        }
+
+        lastState = state;
+        lastStateTime = now;
+    }
+
+    _goToLineStart(msg);
+
+    outputStream.write(msg);
+});

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/frontend/ignite_modules/README.txt
----------------------------------------------------------------------
diff --git a/modules/web-console/frontend/ignite_modules/README.txt b/modules/web-console/frontend/ignite_modules/README.txt
new file mode 100644
index 0000000..365abc7
--- /dev/null
+++ b/modules/web-console/frontend/ignite_modules/README.txt
@@ -0,0 +1,6 @@
+Ignite Web Console Modules
+======================================
+
+If you are are planning to create or use custom modules you need to copy them in this folder before build.
+
+This is default folder for user modules.

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/frontend/ignite_modules/index.js
----------------------------------------------------------------------
diff --git a/modules/web-console/frontend/ignite_modules/index.js b/modules/web-console/frontend/ignite_modules/index.js
new file mode 100644
index 0000000..c38d2d4
--- /dev/null
+++ b/modules/web-console/frontend/ignite_modules/index.js
@@ -0,0 +1,27 @@
+/*
+ * 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';
+
+/* ignite:modules */
+/* endignite */
+
+angular
+.module('ignite-console.modules', [
+    /* ignite-console:modules */
+    /* endignite */
+]);

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/frontend/package.json
----------------------------------------------------------------------
diff --git a/modules/web-console/frontend/package.json b/modules/web-console/frontend/package.json
new file mode 100644
index 0000000..7ea2893
--- /dev/null
+++ b/modules/web-console/frontend/package.json
@@ -0,0 +1,125 @@
+{
+  "name": "ignite-web-console",
+  "version": "1.0.0",
+  "description": "Interactive Web console for configuration, executing SQL queries and monitoring of Apache Ignite Cluster",
+  "private": true,
+  "scripts": {
+    "dev": "cross-env NODE_ENV=development gulp watch",
+    "build": "cross-env NODE_ENV=production gulp build",
+    "test": "karma start ./test/karma.conf.js",
+    "eslint": "eslint --format node_modules/eslint-friendly-formatter gulpfile.babel.js/ app/ controllers/ generator/ ignite_modules/ ignite_modules_temp/ -- --eff-by-issue"
+  },
+  "author": "",
+  "contributors": [
+    {
+      "name": "",
+      "email": ""
+    }
+  ],
+  "license": "Apache-2.0",
+  "keywords": "grid",
+  "homepage": "https://ignite.apache.org/",
+  "engines": {
+    "npm": "^3.x.x",
+    "node": "^4.x.x"
+  },
+  "os": [
+    "darwin",
+    "linux",
+    "win32"
+  ],
+  "dependencies": {
+    "angular": "^1.5.5",
+    "angular-acl": "^0.1.7",
+    "angular-animate": "^1.5.5",
+    "angular-aria": "^1.5.5",
+    "angular-cookies": "^1.5.5",
+    "angular-drag-and-drop-lists": "^1.4.0",
+    "angular-gridster": "^0.13.3",
+    "angular-motion": "^0.4.4",
+    "angular-nvd3": "^1.0.7",
+    "angular-retina": "^0.3.13",
+    "angular-sanitize": "^1.5.5",
+    "angular-smart-table": "^2.1.8",
+    "angular-socket-io": "^0.7.0",
+    "angular-strap": "^2.3.8",
+    "angular-touch": "^1.5.5",
+    "angular-tree-control": "^0.2.26",
+    "angular-ui-grid": "^3.1.1",
+    "angular-ui-router": "^0.3.1",
+    "bootstrap-sass": "^3.3.6",
+    "brace": "^0.8.0",
+    "es6-promise": "^3.0.2",
+    "file-saver": "^1.3.2",
+    "font-awesome": "^4.6.3",
+    "glob": "^7.0.3",
+    "jquery": "^3.0.0",
+    "jszip": "^3.0.0",
+    "lodash": "^4.8.2",
+    "nvd3": "^1.8.3",
+    "query-command-supported": "^1.0.0",
+    "raleway-webfont": "^3.0.1",
+    "roboto-font": "^0.1.0",
+    "socket.io-client": "^1.4.6",
+    "ui-router-metatags": "^1.0.3"
+  },
+  "devDependencies": {
+    "assets-webpack-plugin": "^3.2.0",
+    "autoprefixer-core": "^6.0.1",
+    "babel-core": "^6.7.6",
+    "babel-eslint": "^6.0.4",
+    "babel-loader": "^6.2.4",
+    "babel-plugin-add-module-exports": "^0.2.1",
+    "babel-plugin-transform-builtin-extend": "^1.1.0",
+    "babel-plugin-transform-runtime": "^6.7.5",
+    "babel-polyfill": "^6.7.4",
+    "babel-preset-angular": "^6.0.15",
+    "babel-preset-es2015": "^6.9.0",
+    "babel-runtime": "^6.6.1",
+    "chai": "^3.5.0",
+    "cross-env": "^1.0.7",
+    "css-loader": "^0.23.0",
+    "eslint": "^2.9.0",
+    "eslint-friendly-formatter": "^2.0.5",
+    "eslint-loader": "^1.0.0",
+    "expose-loader": "^0.7.1",
+    "extract-text-webpack-plugin": "^1.0.1",
+    "file-loader": "^0.9.0",
+    "gulp": "^3.9.1",
+    "gulp-eslint": "^2.0.0",
+    "gulp-inject": "^4.0.0",
+    "gulp-jade": "^1.1.0",
+    "gulp-rimraf": "^0.2.0",
+    "gulp-sequence": "^0.4.1",
+    "gulp-util": "^3.0.7",
+    "html-loader": "^0.4.3",
+    "html-webpack-plugin": "^2.21.0",
+    "jade": "^1.11.0",
+    "jade-html-loader": "0.0.3",
+    "jasmine-core": "^2.4.1",
+    "json-loader": "^0.5.4",
+    "karma": "^0.13.22",
+    "karma-babel-preprocessor": "^6.0.1",
+    "karma-jasmine": "^1.0.2",
+    "karma-mocha": "^1.0.1",
+    "karma-phantomjs-launcher": "^1.0.0",
+    "karma-teamcity-reporter": "^1.0.0",
+    "karma-webpack": "^1.7.0",
+    "mocha": "~2.5.3",
+    "mocha-teamcity-reporter": "^1.0.0",
+    "morgan": "^1.7.0",
+    "ngtemplate-loader": "^1.3.1",
+    "node-sass": "^3.4.2",
+    "phantomjs-prebuilt": "^2.1.7",
+    "postcss-loader": "^0.9.1",
+    "require-dir": "^0.3.0",
+    "resolve-url-loader": "^1.4.3",
+    "sass-loader": "^3.1.1",
+    "should": "^9.0.2",
+    "style-loader": "^0.13.1",
+    "url": "^0.11.0",
+    "url-loader": "^0.5.6",
+    "webpack": "^1.13.1",
+    "webpack-dev-server": "^1.15.0"
+  }
+}

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/frontend/public/favicon.ico
----------------------------------------------------------------------
diff --git a/modules/web-console/frontend/public/favicon.ico b/modules/web-console/frontend/public/favicon.ico
new file mode 100644
index 0000000..b36f8d7
Binary files /dev/null and b/modules/web-console/frontend/public/favicon.ico differ

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/frontend/public/images/cache.png
----------------------------------------------------------------------
diff --git a/modules/web-console/frontend/public/images/cache.png b/modules/web-console/frontend/public/images/cache.png
new file mode 100644
index 0000000..83fd987
Binary files /dev/null and b/modules/web-console/frontend/public/images/cache.png differ

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/frontend/public/images/cluster.png
----------------------------------------------------------------------
diff --git a/modules/web-console/frontend/public/images/cluster.png b/modules/web-console/frontend/public/images/cluster.png
new file mode 100644
index 0000000..2d8b860
Binary files /dev/null and b/modules/web-console/frontend/public/images/cluster.png differ

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/frontend/public/images/docker.png
----------------------------------------------------------------------
diff --git a/modules/web-console/frontend/public/images/docker.png b/modules/web-console/frontend/public/images/docker.png
new file mode 100644
index 0000000..afc5df4
Binary files /dev/null and b/modules/web-console/frontend/public/images/docker.png differ

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/frontend/public/images/domains.png
----------------------------------------------------------------------
diff --git a/modules/web-console/frontend/public/images/domains.png b/modules/web-console/frontend/public/images/domains.png
new file mode 100644
index 0000000..39abfcb
Binary files /dev/null and b/modules/web-console/frontend/public/images/domains.png differ

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/frontend/public/images/igfs.png
----------------------------------------------------------------------
diff --git a/modules/web-console/frontend/public/images/igfs.png b/modules/web-console/frontend/public/images/igfs.png
new file mode 100644
index 0000000..47c659e
Binary files /dev/null and b/modules/web-console/frontend/public/images/igfs.png differ

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/frontend/public/images/ignite-logo.png
----------------------------------------------------------------------
diff --git a/modules/web-console/frontend/public/images/ignite-logo.png b/modules/web-console/frontend/public/images/ignite-logo.png
new file mode 100644
index 0000000..ea08d1b
Binary files /dev/null and b/modules/web-console/frontend/public/images/ignite-logo.png differ

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/frontend/public/images/ignite-logo@2x.png
----------------------------------------------------------------------
diff --git a/modules/web-console/frontend/public/images/ignite-logo@2x.png b/modules/web-console/frontend/public/images/ignite-logo@2x.png
new file mode 100644
index 0000000..10005db
Binary files /dev/null and b/modules/web-console/frontend/public/images/ignite-logo@2x.png differ

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/frontend/public/images/ignite-puzzle.png
----------------------------------------------------------------------
diff --git a/modules/web-console/frontend/public/images/ignite-puzzle.png b/modules/web-console/frontend/public/images/ignite-puzzle.png
new file mode 100644
index 0000000..0989d29
Binary files /dev/null and b/modules/web-console/frontend/public/images/ignite-puzzle.png differ

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/frontend/public/images/java.png
----------------------------------------------------------------------
diff --git a/modules/web-console/frontend/public/images/java.png b/modules/web-console/frontend/public/images/java.png
new file mode 100644
index 0000000..ddb3b8e
Binary files /dev/null and b/modules/web-console/frontend/public/images/java.png differ

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/frontend/public/images/pb-ignite.png
----------------------------------------------------------------------
diff --git a/modules/web-console/frontend/public/images/pb-ignite.png b/modules/web-console/frontend/public/images/pb-ignite.png
new file mode 100644
index 0000000..55f6746
Binary files /dev/null and b/modules/web-console/frontend/public/images/pb-ignite.png differ

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/frontend/public/images/pb-ignite@2x.png
----------------------------------------------------------------------
diff --git a/modules/web-console/frontend/public/images/pb-ignite@2x.png b/modules/web-console/frontend/public/images/pb-ignite@2x.png
new file mode 100644
index 0000000..ffcff38
Binary files /dev/null and b/modules/web-console/frontend/public/images/pb-ignite@2x.png differ

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/frontend/public/images/query-chart.png
----------------------------------------------------------------------
diff --git a/modules/web-console/frontend/public/images/query-chart.png b/modules/web-console/frontend/public/images/query-chart.png
new file mode 100644
index 0000000..c6e4cce
Binary files /dev/null and b/modules/web-console/frontend/public/images/query-chart.png differ

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/frontend/public/images/query-metadata.png
----------------------------------------------------------------------
diff --git a/modules/web-console/frontend/public/images/query-metadata.png b/modules/web-console/frontend/public/images/query-metadata.png
new file mode 100644
index 0000000..698cd6e
Binary files /dev/null and b/modules/web-console/frontend/public/images/query-metadata.png differ

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/frontend/public/images/query-table.png
----------------------------------------------------------------------
diff --git a/modules/web-console/frontend/public/images/query-table.png b/modules/web-console/frontend/public/images/query-table.png
new file mode 100644
index 0000000..53becda
Binary files /dev/null and b/modules/web-console/frontend/public/images/query-table.png differ

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/frontend/public/images/summary.png
----------------------------------------------------------------------
diff --git a/modules/web-console/frontend/public/images/summary.png b/modules/web-console/frontend/public/images/summary.png
new file mode 100644
index 0000000..ff88438
Binary files /dev/null and b/modules/web-console/frontend/public/images/summary.png differ

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/frontend/public/images/xml.png
----------------------------------------------------------------------
diff --git a/modules/web-console/frontend/public/images/xml.png b/modules/web-console/frontend/public/images/xml.png
new file mode 100644
index 0000000..029065e
Binary files /dev/null and b/modules/web-console/frontend/public/images/xml.png differ

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/frontend/public/stylesheets/_bootstrap-custom.scss
----------------------------------------------------------------------
diff --git a/modules/web-console/frontend/public/stylesheets/_bootstrap-custom.scss b/modules/web-console/frontend/public/stylesheets/_bootstrap-custom.scss
new file mode 100644
index 0000000..3b52821
--- /dev/null
+++ b/modules/web-console/frontend/public/stylesheets/_bootstrap-custom.scss
@@ -0,0 +1,65 @@
+/*
+ * 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.
+ */
+
+// Core variables and mixins
+@import "bootstrap-variables";
+@import "../../node_modules/bootstrap-sass/assets/stylesheets/bootstrap/mixins";
+
+// Reset and dependencies
+@import "../../node_modules/bootstrap-sass/assets/stylesheets/bootstrap/normalize";
+@import "../../node_modules/bootstrap-sass/assets/stylesheets/bootstrap/print";
+
+// Core CSS
+@import "../../node_modules/bootstrap-sass/assets/stylesheets/bootstrap/scaffolding";
+@import "../../node_modules/bootstrap-sass/assets/stylesheets/bootstrap/type";
+@import "../../node_modules/bootstrap-sass/assets/stylesheets/bootstrap/code";
+@import "../../node_modules/bootstrap-sass/assets/stylesheets/bootstrap/grid";
+@import "../../node_modules/bootstrap-sass/assets/stylesheets/bootstrap/tables";
+@import "../../node_modules/bootstrap-sass/assets/stylesheets/bootstrap/forms";
+@import "../../node_modules/bootstrap-sass/assets/stylesheets/bootstrap/buttons";
+
+// Components
+@import "../../node_modules/bootstrap-sass/assets/stylesheets/bootstrap/component-animations";
+@import "../../node_modules/bootstrap-sass/assets/stylesheets/bootstrap/dropdowns";
+@import "../../node_modules/bootstrap-sass/assets/stylesheets/bootstrap/button-groups";
+@import "../../node_modules/bootstrap-sass/assets/stylesheets/bootstrap/input-groups";
+@import "../../node_modules/bootstrap-sass/assets/stylesheets/bootstrap/navs";
+@import "../../node_modules/bootstrap-sass/assets/stylesheets/bootstrap/navbar";
+@import "../../node_modules/bootstrap-sass/assets/stylesheets/bootstrap/pagination";
+@import "../../node_modules/bootstrap-sass/assets/stylesheets/bootstrap/pager";
+@import "../../node_modules/bootstrap-sass/assets/stylesheets/bootstrap/labels";
+@import "../../node_modules/bootstrap-sass/assets/stylesheets/bootstrap/badges";
+@import "../../node_modules/bootstrap-sass/assets/stylesheets/bootstrap/jumbotron";
+@import "../../node_modules/bootstrap-sass/assets/stylesheets/bootstrap/thumbnails";
+@import "../../node_modules/bootstrap-sass/assets/stylesheets/bootstrap/alerts";
+@import "../../node_modules/bootstrap-sass/assets/stylesheets/bootstrap/progress-bars";
+@import "../../node_modules/bootstrap-sass/assets/stylesheets/bootstrap/media";
+@import "../../node_modules/bootstrap-sass/assets/stylesheets/bootstrap/list-group";
+@import "../../node_modules/bootstrap-sass/assets/stylesheets/bootstrap/panels";
+@import "../../node_modules/bootstrap-sass/assets/stylesheets/bootstrap/responsive-embed";
+@import "../../node_modules/bootstrap-sass/assets/stylesheets/bootstrap/wells";
+@import "../../node_modules/bootstrap-sass/assets/stylesheets/bootstrap/close";
+
+// Components w/ JavaScript
+@import "../../node_modules/bootstrap-sass/assets/stylesheets/bootstrap/modals";
+@import "../../node_modules/bootstrap-sass/assets/stylesheets/bootstrap/tooltip";
+@import "../../node_modules/bootstrap-sass/assets/stylesheets/bootstrap/popovers";
+@import "../../node_modules/bootstrap-sass/assets/stylesheets/bootstrap/carousel";
+
+// Utility classes
+@import "../../node_modules/bootstrap-sass/assets/stylesheets/bootstrap/utilities";
+@import "../../node_modules/bootstrap-sass/assets/stylesheets/bootstrap/responsive-utilities";

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/frontend/public/stylesheets/_bootstrap-variables.scss
----------------------------------------------------------------------
diff --git a/modules/web-console/frontend/public/stylesheets/_bootstrap-variables.scss b/modules/web-console/frontend/public/stylesheets/_bootstrap-variables.scss
new file mode 100644
index 0000000..07e8c51
--- /dev/null
+++ b/modules/web-console/frontend/public/stylesheets/_bootstrap-variables.scss
@@ -0,0 +1,891 @@
+/*
+ * 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.
+ */
+
+$bootstrap-sass-asset-helper: false !default;
+//
+// Variables
+// --------------------------------------------------
+
+
+//== Colors
+//
+//## Gray and brand colors for use across Bootstrap.
+
+$gray-base:              #000 !default;
+$gray-darker:            lighten($gray-base, 13.5%) !default; // #222
+$gray-dark:              lighten($gray-base, 20%) !default;   // #333
+$gray:                   lighten($gray-base, 33.5%) !default; // #555
+$gray-light:             lighten($gray-base, 46.7%) !default; // #777
+$gray-lighter:           lighten($gray-base, 93.5%) !default; // #eee
+
+$brand-primary:         #ec1c24 !default;
+$brand-success:         #50af51 !default;
+$brand-info:            #248fb2 !default;
+$brand-warning:         #f0ad4e !default;
+$brand-danger:          #d9534f !default;
+
+
+//== Scaffolding
+//
+//## Settings for some of the most global styles.
+
+//** Background color for `<body>`.
+$body-bg:               #f9f9f9 !default;
+//** Global text color on `<body>`.
+$text-color:            $gray-dark !default;
+
+//** Global textual link color.
+$link-color:            $brand-primary !default;
+//** Link hover color set via `darken()` function.
+$link-hover-color:      darken($link-color, 15%) !default;
+//** Link hover decoration.
+$link-hover-decoration: underline !default;
+
+
+//== Typography
+//
+//## Font, line-height, and color for body text, headings, and more.
+
+$font-family-sans-serif:  Roboto_slab, sans-serif !default;
+$font-family-serif:       Roboto_slab, serif !default;
+//** Default monospace fonts for `<code>`, `<kbd>`, and `<pre>`.
+$font-family-monospace:   Menlo, Monaco, Consolas, "Courier New", monospace !default;
+$font-family-base:        $font-family-sans-serif !default;
+
+$font-size-base:          14px !default;
+$font-size-large:         ceil(($font-size-base * 1.25)) !default; // ~18px
+$font-size-small:         ceil(($font-size-base * 0.85)) !default; // ~12px
+
+$font-size-h1:            floor(($font-size-base * 2.6)) !default; // ~36px
+$font-size-h2:            floor(($font-size-base * 2.15)) !default; // ~30px
+$font-size-h3:            ceil(($font-size-base * 1.7)) !default; // ~24px
+$font-size-h4:            ceil(($font-size-base * 1.25)) !default; // ~18px
+$font-size-h5:            $font-size-base !default;
+$font-size-h6:            ceil(($font-size-base * 0.85)) !default; // ~12px
+
+//** Unit-less `line-height` for use in components like buttons.
+$line-height-base:        1.428571429 !default; // 20/14
+//** Computed "line-height" (`font-size` * `line-height`) for use with `margin`, `padding`, etc.
+$line-height-computed:    floor(($font-size-base * $line-height-base)) !default; // ~20px
+
+//** By default, this inherits from the `<body>`.
+$headings-font-family:    inherit !default;
+$headings-font-weight:    500 !default;
+$headings-line-height:    1.1 !default;
+$headings-color:          inherit !default;
+
+
+//== Iconography
+//
+//## Specify custom location and filename of the included Glyphicons icon font. Useful for those including Bootstrap via Bower.
+
+//** Load fonts from this directory.
+
+// [converter] If $bootstrap-sass-asset-helper if used, provide path relative to the assets load path.
+// [converter] This is because some asset helpers, such as Sprockets, do not work with file-relative paths.
+$icon-font-path: if($bootstrap-sass-asset-helper, "bootstrap/", "../fonts/bootstrap/") !default;
+
+//** File name for all font files.
+$icon-font-name:          "glyphicons-halflings-regular" !default;
+//** Element ID within SVG icon file.
+$icon-font-svg-id:        "glyphicons_halflingsregular" !default;
+
+
+//== Components
+//
+//## Define common padding and border radius sizes and more. Values based on 14px text and 1.428 line-height (~20px to start).
+
+$padding-base-vertical:     6px !default;
+$padding-base-horizontal:   12px !default;
+
+$padding-large-vertical:    10px !default;
+$padding-large-horizontal:  16px !default;
+
+$padding-small-vertical:    5px !default;
+$padding-small-horizontal:  10px !default;
+
+$padding-xs-vertical:       1px !default;
+$padding-xs-horizontal:     5px !default;
+
+$line-height-large:         1.3333333 !default; // extra decimals for Win 8.1 Chrome
+$line-height-small:         1.5 !default;
+
+$border-radius-base:        4px !default;
+$border-radius-large:       6px !default;
+$border-radius-small:       3px !default;
+
+//** Global color for active items (e.g., navs or dropdowns).
+$component-active-color:    $link-color !default;
+//** Global background color for active items (e.g., navs or dropdowns).
+$component-active-bg:       $brand-primary !default;
+
+//** Width of the `border` for generating carets that indicator dropdowns.
+$caret-width-base:          4px !default;
+//** Carets increase slightly in size for larger components.
+$caret-width-large:         5px !default;
+
+
+//== Tables
+//
+//## Customizes the `.table` component with basic values, each used across all table variations.
+
+//** Padding for `<th>`s and `<td>`s.
+$table-cell-padding:            8px !default;
+//** Padding for cells in `.table-condensed`.
+$table-condensed-cell-padding:  5px !default;
+
+//** Default background color used for all tables.
+$table-bg:                      transparent !default;
+//** Background color used for `.table-striped`.
+$table-bg-accent:               #f9f9f9 !default;
+//** Background color used for `.table-hover`.
+$table-bg-hover:                #f5f5f5 !default;
+$table-bg-active:               $table-bg-hover !default;
+
+//** Border color for table and cell borders.
+$table-border-color:            #ddd !default;
+
+
+//== Buttons
+//
+//## For each of Bootstrap's buttons, define text, background and border color.
+
+$btn-font-weight:                normal !default;
+
+$btn-default-color:              #333 !default;
+$btn-default-bg:                 #fff !default;
+$btn-default-border:             #ccc !default;
+
+$btn-primary-color:              #fff !default;
+$btn-primary-bg:                 $brand-primary !default;
+$btn-primary-border:             darken($btn-primary-bg, 15%) !default;
+
+$btn-success-color:              #fff !default;
+$btn-success-bg:                 $brand-success !default;
+$btn-success-border:             darken($btn-success-bg, 5%) !default;
+
+$btn-info-color:                 #fff !default;
+$btn-info-bg:                    $brand-info !default;
+$btn-info-border:                darken($btn-info-bg, 5%) !default;
+
+$btn-warning-color:              #fff !default;
+$btn-warning-bg:                 $brand-warning !default;
+$btn-warning-border:             darken($btn-warning-bg, 5%) !default;
+
+$btn-danger-color:               #fff !default;
+$btn-danger-bg:                  $brand-danger !default;
+$btn-danger-border:              darken($btn-danger-bg, 5%) !default;
+
+$btn-link-disabled-color:        $gray-light !default;
+
+// Allows for customizing button radius independently from global border radius
+$btn-border-radius-base:         $border-radius-base !default;
+$btn-border-radius-large:        $border-radius-large !default;
+$btn-border-radius-small:        $border-radius-small !default;
+
+
+//== Forms
+//
+//##
+
+//** `<input>` background color
+$input-bg:                       #fff !default;
+//** `<input disabled>` background color
+$input-bg-disabled:              $gray-lighter !default;
+
+//** Text color for `<input>`s
+$input-color:                    $gray !default;
+//** `<input>` border color
+$input-border:                   #ccc !default;
+
+// TODO: Rename `$input-border-radius` to `$input-border-radius-base` in v4
+//** Default `.form-control` border radius
+// This has no effect on `<select>`s in some browsers, due to the limited stylability of `<select>`s in CSS.
+$input-border-radius:            $border-radius-base !default;
+//** Large `.form-control` border radius
+$input-border-radius-large:      $border-radius-large !default;
+//** Small `.form-control` border radius
+$input-border-radius-small:      $border-radius-small !default;
+
+//** Border color for inputs on focus
+$input-border-focus:             #66afe9 !default;
+
+//** Placeholder text color
+$input-color-placeholder:        #999 !default;
+
+//** Default `.form-control` height
+$input-height-base:              ($line-height-computed + ($padding-base-vertical * 2) + 2) !default;
+//** Large `.form-control` height
+$input-height-large:             (ceil($font-size-large * $line-height-large) + ($padding-large-vertical * 2) + 2) !default;
+//** Small `.form-control` height
+$input-height-small:             (floor($font-size-small * $line-height-small) + ($padding-small-vertical * 2) + 2) !default;
+
+//** `.form-group` margin
+$form-group-margin-bottom:       15px !default;
+
+$legend-color:                   $gray-dark !default;
+$legend-border-color:            #e5e5e5 !default;
+
+//** Background color for textual input addons
+$input-group-addon-bg:           $gray-lighter !default;
+//** Border color for textual input addons
+$input-group-addon-border-color: $input-border !default;
+
+//** Disabled cursor for form controls and buttons.
+$cursor-disabled:                not-allowed !default;
+
+
+//== Dropdowns
+//
+//## Dropdown menu container and contents.
+
+//** Background for the dropdown menu.
+$dropdown-bg:                    #fff !default;
+//** Dropdown menu `border-color`.
+$dropdown-border:                rgba(0,0,0,.15) !default;
+//** Dropdown menu `border-color` **for IE8**.
+$dropdown-fallback-border:       #ccc !default;
+//** Divider color for between dropdown items.
+$dropdown-divider-bg:            #e5e5e5 !default;
+
+//** Dropdown link text color.
+$dropdown-link-color:            #555 !default;
+//** Hover color for dropdown links.
+$dropdown-link-hover-color:      $link-hover-color !default;
+//** Hover background for dropdown links.
+$dropdown-link-hover-bg:         transparent !default;
+
+//** Active dropdown menu item text color.
+$dropdown-link-active-color:     $component-active-color !default;
+//** Active dropdown menu item background color.
+$dropdown-link-active-bg:        transparent !default;
+
+//** Disabled dropdown menu item background color.
+$dropdown-link-disabled-color:   $gray-light !default;
+
+//** Text color for headers within dropdown menus.
+$dropdown-header-color:          $gray-light !default;
+
+//** Deprecated `$dropdown-caret-color` as of v3.1.0
+$dropdown-caret-color:           #000 !default;
+
+
+//-- Z-index master list
+//
+// Warning: Avoid customizing these values. They're used for a bird's eye view
+// of components dependent on the z-axis and are designed to all work together.
+//
+// Note: These variables are not generated into the Customizer.
+
+$zindex-navbar:            1000 !default;
+$zindex-dropdown:          1002 !default;
+$zindex-popover:           1060 !default;
+$zindex-tooltip:           1070 !default;
+$zindex-navbar-fixed:      1030 !default;
+$zindex-modal-background:  1040 !default;
+$zindex-modal:             1050 !default;
+
+
+//== Media queries breakpoints
+//
+//## Define the breakpoints at which your layout will change, adapting to different screen sizes.
+
+// Extra small screen / phone
+//** Deprecated `$screen-xs` as of v3.0.1
+$screen-xs:                  480px !default;
+//** Deprecated `$screen-xs-min` as of v3.2.0
+$screen-xs-min:              $screen-xs !default;
+//** Deprecated `$screen-phone` as of v3.0.1
+$screen-phone:               $screen-xs-min !default;
+
+// Small screen / tablet
+//** Deprecated `$screen-sm` as of v3.0.1
+$screen-sm:                  768px !default;
+$screen-sm-min:              $screen-sm !default;
+//** Deprecated `$screen-tablet` as of v3.0.1
+$screen-tablet:              $screen-sm-min !default;
+
+// Medium screen / desktop
+//** Deprecated `$screen-md` as of v3.0.1
+$screen-md:                  992px !default;
+$screen-md-min:              $screen-md !default;
+//** Deprecated `$screen-desktop` as of v3.0.1
+$screen-desktop:             $screen-md-min !default;
+
+// Large screen / wide desktop
+//** Deprecated `$screen-lg` as of v3.0.1
+$screen-lg:                  1200px !default;
+$screen-lg-min:              $screen-lg !default;
+//** Deprecated `$screen-lg-desktop` as of v3.0.1
+$screen-lg-desktop:          $screen-lg-min !default;
+
+// So media queries don't overlap when required, provide a maximum
+$screen-xs-max:              ($screen-sm-min - 1) !default;
+$screen-sm-max:              ($screen-md-min - 1) !default;
+$screen-md-max:              ($screen-lg-min - 1) !default;
+
+
+//== Grid system
+//
+//## Define your custom responsive grid.
+
+//** Number of columns in the grid.
+$grid-columns:              12 !default;
+//** Padding between columns. Gets divided in half for the left and right.
+$grid-gutter-width:         0 !default;
+// Navbar collapse
+//** Point at which the navbar becomes uncollapsed.
+$grid-float-breakpoint:     $screen-sm-min !default;
+//** Point at which the navbar begins collapsing.
+$grid-float-breakpoint-max: ($grid-float-breakpoint - 1) !default;
+
+
+//== Container sizes
+//
+//## Define the maximum width of `.container` for different screen sizes.
+
+// Small screen / tablet
+$container-tablet:             (720px + $grid-gutter-width) !default;
+//** For `$screen-sm-min` and up.
+$container-sm:                 $container-tablet !default;
+
+// Medium screen / desktop
+$container-desktop:            (940px + $grid-gutter-width) !default;
+//** For `$screen-md-min` and up.
+$container-md:                 $container-desktop !default;
+
+// Large screen / wide desktop
+$container-large-desktop:      (1140px + $grid-gutter-width) !default;
+//** For `$screen-lg-min` and up.
+$container-lg:                 $container-large-desktop !default;
+
+
+//== Navbar
+//
+//##
+
+// Basics of a navbar
+$navbar-height:                    50px !default;
+$navbar-margin-bottom:             $line-height-computed !default;
+$navbar-border-radius:             $border-radius-base !default;
+$navbar-padding-horizontal:        floor(($grid-gutter-width / 2)) !default;
+$navbar-padding-vertical:          (($navbar-height - $line-height-computed) / 2) !default;
+$navbar-collapse-max-height:       340px !default;
+
+$navbar-default-color:             #bbb !default;
+$navbar-default-bg:                #f8f8f8 !default;
+$navbar-default-border:            darken($navbar-default-bg, 6.5%) !default;
+
+// Navbar links
+$navbar-default-link-color:                #bbb !default;
+$navbar-default-link-hover-color:          $link-hover-color !default;
+$navbar-default-link-hover-bg:             transparent !default;
+$navbar-default-link-active-color:         $component-active-color !default;
+$navbar-default-link-active-bg:            darken($navbar-default-bg, 6.5%) !default;
+$navbar-default-link-disabled-color:       #ccc !default;
+$navbar-default-link-disabled-bg:          transparent !default;
+
+// Navbar brand label
+$navbar-default-brand-color:               $navbar-default-link-color !default;
+$navbar-default-brand-hover-color:         darken($link-color, 15%) !default;
+$navbar-default-brand-hover-bg:            transparent !default;
+
+// Navbar toggle
+$navbar-default-toggle-hover-bg:           #ddd !default;
+$navbar-default-toggle-icon-bar-bg:        #888 !default;
+$navbar-default-toggle-border-color:       #ddd !default;
+
+
+//=== Inverted navbar
+// Reset inverted navbar basics
+$navbar-inverse-color:                      lighten($gray-light, 15%) !default;
+$navbar-inverse-bg:                         #222 !default;
+$navbar-inverse-border:                     darken($navbar-inverse-bg, 10%) !default;
+
+// Inverted navbar links
+$navbar-inverse-link-color:                 lighten($gray-light, 15%) !default;
+$navbar-inverse-link-hover-color:           #fff !default;
+$navbar-inverse-link-hover-bg:              transparent !default;
+$navbar-inverse-link-active-color:          $navbar-inverse-link-hover-color !default;
+$navbar-inverse-link-active-bg:             darken($navbar-inverse-bg, 10%) !default;
+$navbar-inverse-link-disabled-color:        #444 !default;
+$navbar-inverse-link-disabled-bg:           transparent !default;
+
+// Inverted navbar brand label
+$navbar-inverse-brand-color:                $navbar-inverse-link-color !default;
+$navbar-inverse-brand-hover-color:          #fff !default;
+$navbar-inverse-brand-hover-bg:             transparent !default;
+
+// Inverted navbar toggle
+$navbar-inverse-toggle-hover-bg:            #333 !default;
+$navbar-inverse-toggle-icon-bar-bg:         #fff !default;
+$navbar-inverse-toggle-border-color:        #333 !default;
+
+
+//== Navs
+//
+//##
+
+//=== Shared nav styles
+$nav-link-padding:                          10px 15px !default;
+$nav-link-hover-bg:                         transparent !default;
+
+$nav-disabled-link-color:                   $gray-light !default;
+$nav-disabled-link-hover-color:             $gray-light !default;
+
+//== Tabs
+$nav-tabs-border-color:                     #ddd !default;
+
+$nav-tabs-link-hover-border-color:          $gray-lighter !default;
+
+$nav-tabs-active-link-hover-bg:             $body-bg !default;
+$nav-tabs-active-link-hover-color:          $gray !default;
+$nav-tabs-active-link-hover-border-color:   #ddd !default;
+
+$nav-tabs-justified-link-border-color:            #ddd !default;
+$nav-tabs-justified-active-link-border-color:     $body-bg !default;
+
+//== Pills
+$nav-pills-border-radius:                   $border-radius-base !default;
+$nav-pills-active-link-hover-bg:            $component-active-bg !default;
+$nav-pills-active-link-hover-color:         $component-active-color !default;
+
+
+//== Pagination
+//
+//##
+
+$pagination-color:                     $link-color !default;
+$pagination-bg:                        #fff !default;
+$pagination-border:                    #ddd !default;
+
+$pagination-hover-color:               $link-hover-color !default;
+$pagination-hover-bg:                  $gray-lighter !default;
+$pagination-hover-border:              #ddd !default;
+
+$pagination-active-color:              #fff !default;
+$pagination-active-bg:                 $brand-primary !default;
+$pagination-active-border:             $brand-primary !default;
+
+$pagination-disabled-color:            $gray-light !default;
+$pagination-disabled-bg:               #fff !default;
+$pagination-disabled-border:           #ddd !default;
+
+
+//== Pager
+//
+//##
+
+$pager-bg:                             $pagination-bg !default;
+$pager-border:                         $pagination-border !default;
+$pager-border-radius:                  15px !default;
+
+$pager-hover-bg:                       $pagination-hover-bg !default;
+
+$pager-active-bg:                      $pagination-active-bg !default;
+$pager-active-color:                   $pagination-active-color !default;
+
+$pager-disabled-color:                 $pagination-disabled-color !default;
+
+
+//== Jumbotron
+//
+//##
+
+$jumbotron-padding:              30px !default;
+$jumbotron-color:                inherit !default;
+$jumbotron-bg:                   $gray-lighter !default;
+$jumbotron-heading-color:        inherit !default;
+$jumbotron-font-size:            ceil(($font-size-base * 1.5)) !default;
+$jumbotron-heading-font-size:    ceil(($font-size-base * 4.5)) !default;
+
+
+//== Form states and alerts
+//
+//## Define colors for form feedback states and, by default, alerts.
+
+$state-success-text:             #3c763d !default;
+$state-success-bg:               #dff0d8 !default;
+$state-success-border:           darken(adjust-hue($state-success-bg, -10), 25%) !default;
+
+$state-info-text:                #31708f !default;
+$state-info-bg:                  #d9edf7 !default;
+$state-info-border:              darken(adjust-hue($state-info-bg, -10), 25%) !default;
+
+$state-warning-text:             #8a6d3b !default;
+$state-warning-bg:               #fcf8e3 !default;
+$state-warning-border:           darken(adjust-hue($state-warning-bg, -10), 25%) !default;
+
+$state-danger-text:              #a94442 !default;
+$state-danger-bg:                #f2dede !default;
+$state-danger-border:            darken(adjust-hue($state-danger-bg, -10), 25%) !default;
+
+
+//== Tooltips
+//
+//##
+
+//** Tooltip max width
+$tooltip-max-width:           400px !default;
+//** Tooltip text color
+$tooltip-color:               #000 !default;
+//** Tooltip background color
+$tooltip-bg:                  #f5f5f5 !default;
+$tooltip-opacity:             1 !default;
+
+//** Tooltip arrow width
+$tooltip-arrow-width:         5px !default;
+//** Tooltip arrow color
+$tooltip-arrow-color:         #ccc !default;
+
+
+//== Popovers
+//
+//##
+
+//** Popover body background color
+$popover-bg:                          #fff !default;
+//** Popover maximum width
+$popover-max-width:                   auto !default;
+//** Popover border color
+$popover-border-color:                rgba(0,0,0,.2) !default;
+//** Popover fallback border color
+$popover-fallback-border-color:       #ccc !default;
+
+//** Popover title background color
+$popover-title-bg:                    darken($popover-bg, 3%) !default;
+
+//** Popover arrow width
+$popover-arrow-width:                 10px !default;
+//** Popover arrow color
+$popover-arrow-color:                 $popover-bg !default;
+
+//** Popover outer arrow width
+$popover-arrow-outer-width:           ($popover-arrow-width + 1) !default;
+//** Popover outer arrow color
+$popover-arrow-outer-color:           fade_in($popover-border-color, 0.05) !default;
+//** Popover outer arrow fallback color
+$popover-arrow-outer-fallback-color:  darken($popover-fallback-border-color, 20%) !default;
+
+
+//== Labels
+//
+//##
+
+//** Default label background color
+$label-default-bg:            $gray-light !default;
+//** Primary label background color
+$label-primary-bg:            $brand-primary !default;
+//** Success label background color
+$label-success-bg:            $brand-success !default;
+//** Info label background color
+$label-info-bg:               $brand-info !default;
+//** Warning label background color
+$label-warning-bg:            $brand-warning !default;
+//** Danger label background color
+$label-danger-bg:             $brand-danger !default;
+
+//** Default label text color
+$label-color:                 #fff !default;
+//** Default text color of a linked label
+$label-link-hover-color:      #fff !default;
+
+
+//== Modals
+//
+//##
+
+//** Padding applied to the modal body
+$modal-inner-padding:         15px !default;
+
+//** Padding applied to the modal title
+$modal-title-padding:         15px !default;
+//** Modal title line-height
+$modal-title-line-height:     $line-height-base !default;
+
+//** Background color of modal content area
+$modal-content-bg:                             #fff !default;
+//** Modal content border color
+$modal-content-border-color:                   rgba(0,0,0,.2) !default;
+//** Modal content border color **for IE8**
+$modal-content-fallback-border-color:          #999 !default;
+
+//** Modal backdrop background color
+$modal-backdrop-bg:           #000 !default;
+//** Modal backdrop opacity
+$modal-backdrop-opacity:      .5 !default;
+//** Modal header border color
+$modal-header-border-color:   #e5e5e5 !default;
+//** Modal footer border color
+$modal-footer-border-color:   $modal-header-border-color !default;
+
+$modal-lg:                    900px !default;
+$modal-md:                    600px !default;
+$modal-sm:                    300px !default;
+
+
+//== Alerts
+//
+//## Define alert colors, border radius, and padding.
+
+$alert-padding:               15px !default;
+$alert-border-radius:         $border-radius-base !default;
+$alert-link-font-weight:      bold !default;
+
+$alert-success-bg:            $state-success-bg !default;
+$alert-success-text:          $state-success-text !default;
+$alert-success-border:        $state-success-border !default;
+
+$alert-info-bg:               $state-info-bg !default;
+$alert-info-text:             $state-info-text !default;
+$alert-info-border:           $state-info-border !default;
+
+$alert-warning-bg:            $state-warning-bg !default;
+$alert-warning-text:          $state-warning-text !default;
+$alert-warning-border:        $state-warning-border !default;
+
+$alert-danger-bg:             $state-danger-bg !default;
+$alert-danger-text:           $state-danger-text !default;
+$alert-danger-border:         $state-danger-border !default;
+
+
+//== Progress bars
+//
+//##
+
+//** Background color of the whole progress component
+$progress-bg:                 #f5f5f5 !default;
+//** Progress bar text color
+$progress-bar-color:          #fff !default;
+//** Variable for setting rounded corners on progress bar.
+$progress-border-radius:      $border-radius-base !default;
+
+//** Default progress bar color
+$progress-bar-bg:             $brand-primary !default;
+//** Success progress bar color
+$progress-bar-success-bg:     $brand-success !default;
+//** Warning progress bar color
+$progress-bar-warning-bg:     $brand-warning !default;
+//** Danger progress bar color
+$progress-bar-danger-bg:      $brand-danger !default;
+//** Info progress bar color
+$progress-bar-info-bg:        $brand-info !default;
+
+
+//== List group
+//
+//##
+
+//** Background color on `.list-group-item`
+$list-group-bg:                 #fff !default;
+//** `.list-group-item` border color
+$list-group-border:             #ddd !default;
+//** List group border radius
+$list-group-border-radius:      $border-radius-base !default;
+
+//** Background color of single list items on hover
+$list-group-hover-bg:           #f5f5f5 !default;
+//** Text color of active list items
+$list-group-active-color:       $component-active-color !default;
+//** Background color of active list items
+$list-group-active-bg:          $component-active-bg !default;
+//** Border color of active list elements
+$list-group-active-border:      $list-group-active-bg !default;
+//** Text color for content within active list items
+$list-group-active-text-color:  lighten($list-group-active-bg, 40%) !default;
+
+//** Text color of disabled list items
+$list-group-disabled-color:      $gray-light !default;
+//** Background color of disabled list items
+$list-group-disabled-bg:         $gray-lighter !default;
+//** Text color for content within disabled list items
+$list-group-disabled-text-color: $list-group-disabled-color !default;
+
+$list-group-link-color:         #555 !default;
+$list-group-link-hover-color:   $list-group-link-color !default;
+$list-group-link-heading-color: #333 !default;
+
+
+//== Panels
+//
+//##
+
+$panel-bg:                    #fff !default;
+$panel-body-padding:          15px !default;
+$panel-heading-padding:       10px 15px !default;
+$panel-footer-padding:        $panel-heading-padding !default;
+$panel-border-radius:         $border-radius-base !default;
+
+//** Border color for elements within panels
+$panel-inner-border:          #ddd !default;
+$panel-footer-bg:             #f5f5f5 !default;
+
+$panel-default-text:          $gray-dark !default;
+$panel-default-border:        #ddd !default;
+$panel-default-heading-bg:    #f5f5f5 !default;
+
+$panel-primary-text:          #fff !default;
+$panel-primary-border:        $brand-primary !default;
+$panel-primary-heading-bg:    $brand-primary !default;
+
+$panel-success-text:          $state-success-text !default;
+$panel-success-border:        $state-success-border !default;
+$panel-success-heading-bg:    $state-success-bg !default;
+
+$panel-info-text:             $state-info-text !default;
+$panel-info-border:           $state-info-border !default;
+$panel-info-heading-bg:       $state-info-bg !default;
+
+$panel-warning-text:          $state-warning-text !default;
+$panel-warning-border:        $state-warning-border !default;
+$panel-warning-heading-bg:    $state-warning-bg !default;
+
+$panel-danger-text:           $state-danger-text !default;
+$panel-danger-border:         $state-danger-border !default;
+$panel-danger-heading-bg:     $state-danger-bg !default;
+
+
+//== Thumbnails
+//
+//##
+
+//** Padding around the thumbnail image
+$thumbnail-padding:           4px !default;
+//** Thumbnail background color
+$thumbnail-bg:                $body-bg !default;
+//** Thumbnail border color
+$thumbnail-border:            #ddd !default;
+//** Thumbnail border radius
+$thumbnail-border-radius:     $border-radius-base !default;
+
+//** Custom text color for thumbnail captions
+$thumbnail-caption-color:     $text-color !default;
+//** Padding around the thumbnail caption
+$thumbnail-caption-padding:   9px !default;
+
+
+//== Wells
+//
+//##
+
+$well-bg:                     #f5f5f5 !default;
+$well-border:                 darken($well-bg, 7%) !default;
+
+
+//== Badges
+//
+//##
+
+$badge-color:                 #fff !default;
+//** Linked badge text color on hover
+$badge-link-hover-color:      #fff !default;
+$badge-bg:                    $gray-light !default;
+
+//** Badge text color in active nav link
+$badge-active-color:          $link-color !default;
+//** Badge background color in active nav link
+$badge-active-bg:             #fff !default;
+
+$badge-font-weight:           bold !default;
+$badge-line-height:           1 !default;
+$badge-border-radius:         10px !default;
+
+
+//== Breadcrumbs
+//
+//##
+
+$breadcrumb-padding-vertical:   8px !default;
+$breadcrumb-padding-horizontal: 15px !default;
+//** Breadcrumb background color
+$breadcrumb-bg:                 #f5f5f5 !default;
+//** Breadcrumb text color
+$breadcrumb-color:              #ccc !default;
+//** Text color of current page in the breadcrumb
+$breadcrumb-active-color:       $gray-light !default;
+//** Textual separator for between breadcrumb elements
+$breadcrumb-separator:          "/" !default;
+
+
+//== Carousel
+//
+//##
+
+$carousel-text-shadow:                        none !default;
+
+$carousel-control-color:                      #333 !default;
+$carousel-control-width:                      25% !default;
+$carousel-control-opacity:                    1 !default;
+$carousel-control-font-size:                  20px !default;
+
+$carousel-indicator-active-bg:                #333 !default;
+$carousel-indicator-border-color:             #333 !default;
+
+$carousel-caption-color:                      #333 !default;
+
+
+//== Close
+//
+//##
+
+$close-font-weight:           bold !default;
+$close-color:                 #000 !default;
+$close-text-shadow:           0 1px 0 #fff !default;
+
+
+//== Code
+//
+//##
+
+$code-color:                  #c7254e !default;
+$code-bg:                     #f9f2f4 !default;
+
+$kbd-color:                   #fff !default;
+$kbd-bg:                      #333 !default;
+
+$pre-bg:                      #f5f5f5 !default;
+$pre-color:                   $gray-dark !default;
+$pre-border-color:            #ccc !default;
+$pre-scrollable-max-height:   340px !default;
+
+
+//== Type
+//
+//##
+
+//** Horizontal offset for forms and lists.
+$component-offset-horizontal: 180px !default;
+//** Text muted color
+$text-muted:                  $gray-light !default;
+//** Abbreviations and acronyms border color
+$abbr-border-color:           $gray-light !default;
+//** Headings small color
+$headings-small-color:        $gray-light !default;
+//** Blockquote small color
+$blockquote-small-color:      $gray-light !default;
+//** Blockquote font size
+$blockquote-font-size:        ($font-size-base * 1.25) !default;
+//** Blockquote border color
+$blockquote-border-color:     $gray-lighter !default;
+//** Page header border color
+$page-header-border-color:    $gray-lighter !default;
+//** Width of horizontal description list titles
+$dl-horizontal-offset:        $component-offset-horizontal !default;
+//** Point at which .dl-horizontal becomes horizontal
+$dl-horizontal-breakpoint:    $grid-float-breakpoint !default;
+//** Horizontal line color.
+$hr-border:                   $gray-lighter !default;


[50/52] ignite git commit: Fixed containers version in docker compose file.

Posted by ak...@apache.org.
Fixed containers version in docker compose file.


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

Branch: refs/heads/master
Commit: 769e0be12b61497d456a113307c8cff86128ba50
Parents: 4e1a8ff
Author: Maxim Afanasiev <ma...@gmail.com>
Authored: Thu Sep 8 16:22:45 2016 +0700
Committer: Maxim Afanasiev <ma...@gmail.com>
Committed: Thu Sep 8 16:22:45 2016 +0700

----------------------------------------------------------------------
 modules/web-console/docker/compose/docker-compose.yml | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/ignite/blob/769e0be1/modules/web-console/docker/compose/docker-compose.yml
----------------------------------------------------------------------
diff --git a/modules/web-console/docker/compose/docker-compose.yml b/modules/web-console/docker/compose/docker-compose.yml
index bacd769..4f83ba0 100644
--- a/modules/web-console/docker/compose/docker-compose.yml
+++ b/modules/web-console/docker/compose/docker-compose.yml
@@ -22,7 +22,7 @@ mongodb:
     - ./data/mongo:/data/db
 
 backend:
-  image: ignite/web-console-backend:1.7.0
+  image: ignite/web-console-backend
   links:
     # Link mongodb container as with mongodb hostname.
     - mongodb:mongodb
@@ -49,7 +49,7 @@ backend:
     - mail_auth_pass=""
 
 frontend:
-  image: ignite/web-console-frontend:1.7.0
+  image: ignite/web-console-frontend
   links:
     # Link backend container to proxy backend requests throught nginx container.
     - backend:backend


[22/52] ignite git commit: Web Console beta-3.

Posted by ak...@apache.org.
http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/frontend/views/templates/batch-confirm.jade
----------------------------------------------------------------------
diff --git a/modules/web-console/frontend/views/templates/batch-confirm.jade b/modules/web-console/frontend/views/templates/batch-confirm.jade
new file mode 100644
index 0000000..7451314
--- /dev/null
+++ b/modules/web-console/frontend/views/templates/batch-confirm.jade
@@ -0,0 +1,32 @@
+//-
+    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.
+
+.modal(tabindex='-1' role='dialog')
+    .modal-dialog
+        .modal-content
+            .modal-header
+                button.close(ng-click='cancel()' aria-hidden='true') &times;
+                h4.modal-title Confirmation
+            .modal-body(ng-show='content')
+                p(ng-bind-html='content' style='text-align: center')
+            .modal-footer
+                .checkbox.labelField
+                    label
+                        input(type='checkbox' ng-model='applyToAll')
+                        | Apply to all
+                button.btn.btn-default(id='batch-confirm-btn-cancel' ng-click='cancel()') Cancel
+                button.btn.btn-default(id='batch-confirm-btn-skip' ng-click='skip(applyToAll)') Skip
+                button.btn.btn-primary(id='batch-confirm-btn-overwrite' ng-click='overwrite(applyToAll)') Overwrite

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/frontend/views/templates/clone.jade
----------------------------------------------------------------------
diff --git a/modules/web-console/frontend/views/templates/clone.jade b/modules/web-console/frontend/views/templates/clone.jade
new file mode 100644
index 0000000..d68bf45
--- /dev/null
+++ b/modules/web-console/frontend/views/templates/clone.jade
@@ -0,0 +1,37 @@
+//-
+    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.jade
+
+.modal(tabindex='-1' role='dialog')
+    .modal-dialog
+        .modal-content
+            .modal-header
+                button.close(ng-click='$hide()') &times;
+                h4.modal-title Clone
+            form.form-horizontal.modal-body.row(name='ui.inputForm' novalidate)
+                div
+                    .col-sm-2
+                        label.required.labelFormField New name:&nbsp;
+                    .col-sm-10
+                        .input-tip
+                            +ignite-form-field-input('"copy-new-name"','newName', false, 'true', 'Enter new name')(
+                                data-ignite-form-field-input-autofocus='true'
+                                ignite-on-enter='form.$valid && ok(newName)'
+                            )
+            .modal-footer
+                button.btn.btn-default(id='copy-btn-cancel' ng-click='$hide()') Cancel
+                button.btn.btn-primary(id='copy-btn-confirm' ng-disabled='ui.inputForm.$invalid' ng-click='ok(newName)') Confirm

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/frontend/views/templates/confirm.jade
----------------------------------------------------------------------
diff --git a/modules/web-console/frontend/views/templates/confirm.jade b/modules/web-console/frontend/views/templates/confirm.jade
new file mode 100644
index 0000000..26af061
--- /dev/null
+++ b/modules/web-console/frontend/views/templates/confirm.jade
@@ -0,0 +1,31 @@
+//-
+    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.
+
+.modal(tabindex='-1' role='dialog')
+    .modal-dialog
+        .modal-content
+            .modal-header
+                button.close(ng-click='confirmCancel()' aria-hidden='true') &times;
+                h4.modal-title Confirmation
+            .modal-body(ng-show='content')
+                p(ng-bind-html='content' style='text-align: center;')
+            .modal-footer
+                button#confirm-btn-cancel.btn.btn-default(ng-click='confirmCancel()') Cancel
+
+                button#confirm-btn-no.btn.btn-default(ng-if='yesNo' ng-click='confirmNo()') No
+                button#confirm-btn-yes.btn.btn-primary(ng-if='yesNo' ng-click='confirmYes()') Yes
+
+                button#confirm-btn-ok.btn.btn-primary(ng-if='!yesNo' ng-click='confirmYes()') Confirm

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/frontend/views/templates/demo-info.jade
----------------------------------------------------------------------
diff --git a/modules/web-console/frontend/views/templates/demo-info.jade b/modules/web-console/frontend/views/templates/demo-info.jade
new file mode 100644
index 0000000..100e806
--- /dev/null
+++ b/modules/web-console/frontend/views/templates/demo-info.jade
@@ -0,0 +1,45 @@
+//-
+    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.
+
+.modal.center(role='dialog')
+    .modal-dialog
+        .modal-content
+            #errors-container.modal-header.header
+                button.close(ng-click='close()' aria-hidden='true') &times;
+                h4.modal-title {{title}}
+            .modal-body
+                div(ng-bind-html='message')
+                div(ng-hide='hasAgents')
+                    p &nbsp;
+                    div
+                        h4
+                            i.fa.fa-download.fa-cursor-default
+                            | &nbsp;How To Start Demo
+                        ul
+                            li
+                                a(ng-click='downloadAgent()') #[b Download]
+                                | &nbsp; and unzip ignite-web-agent archive
+                            li #[b Run] shell file ignite-web-agent.{sh|bat}
+                div(ng-show='hasAgents')
+                    h4
+                        i.fa.fa-star-o.fa-cursor-default
+                        | &nbsp;Start Demo
+                    ul
+                        li Web Agent is already started
+                        li Close dialog and try Web Console
+            .modal-footer
+                button.btn.btn-default(ng-class='hasAgents ? "btn-primary" : "btn-default"' ng-click='close()') Close
+                button.btn.btn-primary(ng-hide='hasAgents' ng-click='downloadAgent()') Download agent

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/frontend/views/templates/dropdown.jade
----------------------------------------------------------------------
diff --git a/modules/web-console/frontend/views/templates/dropdown.jade b/modules/web-console/frontend/views/templates/dropdown.jade
new file mode 100644
index 0000000..2ee8616
--- /dev/null
+++ b/modules/web-console/frontend/views/templates/dropdown.jade
@@ -0,0 +1,24 @@
+//-
+    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.
+
+ul.dropdown-menu(tabindex='-1' role='menu' ng-show='content && content.length')
+    li(role='presentation' ui-sref-active='active' ng-class='{divider: item.divider, active: item.active}' ng-repeat='item in content')
+        a(role='menuitem' tabindex='-1' ui-sref='{{item.sref}}' ng-if='!item.action && !item.divider && item.sref' ng-bind='item.text')
+        a(role='menuitem' tabindex='-1' ng-href='{{item.href}}' ng-if='!item.action && !item.divider && item.href' target='{{item.target || ""}}' ng-bind='item.text')
+        a(role='menuitem' tabindex='-1' href='javascript:void(0)' ng-if='!item.action && !item.divider && item.click' ng-click='$eval(item.click);$hide()' ng-bind='item.text')
+        div(role='menuitem' ng-if='item.action')
+            i.fa.pull-right(class='{{ item.action.icon }}' ng-click='item.action.click(item.data)' bs-tooltip data-title='{{ item.action.tooltip }}' data-trigger='hover' data-placement='bottom')
+            div: a(ui-sref='{{ item.sref }}' ng-bind='item.text')

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/frontend/views/templates/getting-started.jade
----------------------------------------------------------------------
diff --git a/modules/web-console/frontend/views/templates/getting-started.jade b/modules/web-console/frontend/views/templates/getting-started.jade
new file mode 100644
index 0000000..98bc265
--- /dev/null
+++ b/modules/web-console/frontend/views/templates/getting-started.jade
@@ -0,0 +1,32 @@
+//-
+    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.
+
+.modal.center(role='dialog')
+    .modal-dialog
+        .modal-content
+            #errors-container.modal-header.header
+                button.close(ng-click='close()' aria-hidden='true') &times;
+                h4.modal-title {{title}}
+            .getting-started
+                .col-xs-12(ng-bind-html='message')
+            .modal-footer
+                .checkbox
+                    label
+                        input(type='checkbox' ng-model='ui.showGettingStarted')
+                        | Show getting started on next login
+                a.btn.btn-primary(ng-disabled='isFirst()' ng-click='!isFirst() && prev()') Prev
+                a.btn.btn-primary(ng-disabled='isLast()' ng-click='!isLast() && next()') Next
+                a.btn.btn-primary(ng-click='close()') Close

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/frontend/views/templates/message.jade
----------------------------------------------------------------------
diff --git a/modules/web-console/frontend/views/templates/message.jade b/modules/web-console/frontend/views/templates/message.jade
new file mode 100644
index 0000000..6dcf445
--- /dev/null
+++ b/modules/web-console/frontend/views/templates/message.jade
@@ -0,0 +1,26 @@
+//-
+    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.
+
+.modal(tabindex='-1' role='dialog')
+    .modal-dialog
+        .modal-content
+            .modal-header
+                button.close(ng-click='$hide()' aria-hidden='true') &times;
+                h4.modal-title {{title}}
+            .modal-body(ng-show='content')
+                p(ng-bind-html='content.join("<br/>")' style='text-align: left;')
+            .modal-footer
+                button.btn.btn-primary(id='confirm-btn-confirm' ng-click='$hide()') Ok

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/frontend/views/templates/pagination.jade
----------------------------------------------------------------------
diff --git a/modules/web-console/frontend/views/templates/pagination.jade b/modules/web-console/frontend/views/templates/pagination.jade
new file mode 100644
index 0000000..08ced60
--- /dev/null
+++ b/modules/web-console/frontend/views/templates/pagination.jade
@@ -0,0 +1,32 @@
+//-
+    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.
+
+nav(ng-if='numPages && pages.length >= 2')
+    ul.pagination
+        li(ng-if='currentPage > 1')
+            a(href='javascript:void(0);' ng-click='selectPage(1)' bs-tooltip='' data-title='First page' data-placement='bottom')
+                i.fa.fa-angle-double-left
+        li(ng-if='currentPage > 1')
+            a(href='javascript:void(0);' ng-click='selectPage(currentPage-1)' bs-tooltip='' data-title='Previous page' data-placement='bottom')
+                i.fa.fa-angle-left
+        li(ng-repeat='page in pages' ng-class='{active: page==currentPage}')
+            a(href='javascript:void(0);' ng-click='selectPage(page)') {{page}}
+        li(ng-if='currentPage < numPages')
+            a(href='javascript:void(0);' ng-click='selectPage(currentPage+1)' bs-tooltip='' data-title='Next page' data-placement='bottom')
+                i.fa.fa-angle-right
+        li(ng-if='currentPage < numPages')
+            a(href='javascript:void(0);' ng-click='selectPage(numPages)' bs-tooltip='' data-title='Last page' data-placement='bottom')
+                i.fa.fa-angle-double-right
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/frontend/views/templates/select.jade
----------------------------------------------------------------------
diff --git a/modules/web-console/frontend/views/templates/select.jade b/modules/web-console/frontend/views/templates/select.jade
new file mode 100644
index 0000000..3feee61
--- /dev/null
+++ b/modules/web-console/frontend/views/templates/select.jade
@@ -0,0 +1,26 @@
+//-
+    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.
+
+ul.select.dropdown-menu(tabindex='-1' ng-show='$isVisible()' role='select')
+    li(ng-if='$showAllNoneButtons || ($isMultiple && $matches.length > 2)')
+        a(id='li-dropdown-select-all' ng-click='$selectAll()') {{$allText}} ({{$matches.length}})
+        a(id='li-dropdown-select-none' ng-click='$selectNone()') {{$noneText}}
+        hr(style='margin: 5px 0')
+    li(role='presentation' ng-repeat='match in $matches')
+        hr(ng-if='match.value == undefined' style='margin: 5px 0')
+        a(id='li-dropdown-item-{{$index}}'  role='menuitem' tabindex='-1' ng-class='{active: $isActive($index)}' ng-click='$select($index, $event)' bs-tooltip='widthIsSufficient && !widthIsSufficient("li-dropdown-item-{{$index}}", $index, match.label) ? match.label : ""' data-placement='bottom')
+            i(class='{{$iconCheckmark}}' ng-if='$isActive($index)' ng-class='{active: $isActive($index)}')
+            span(ng-bind='match.label')

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/frontend/views/templates/validation-error.jade
----------------------------------------------------------------------
diff --git a/modules/web-console/frontend/views/templates/validation-error.jade b/modules/web-console/frontend/views/templates/validation-error.jade
new file mode 100644
index 0000000..13deb9b
--- /dev/null
+++ b/modules/web-console/frontend/views/templates/validation-error.jade
@@ -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.
+
+.popover.validation-error
+    .arrow
+    .popover-content
+        table
+            tr
+                td
+                    label {{content}}&nbsp&nbsp
+                td
+                    button.close(id='popover-btn-close' ng-click='$hide()') &times;

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/pom.xml
----------------------------------------------------------------------
diff --git a/modules/web-console/pom.xml b/modules/web-console/pom.xml
index 5c5cac0..e66252c 100644
--- a/modules/web-console/pom.xml
+++ b/modules/web-console/pom.xml
@@ -32,16 +32,17 @@
 
     <artifactId>ignite-web-console</artifactId>
     <version>1.7.0-SNAPSHOT</version>
+    <url>http://ignite.apache.org</url>
 
     <build>
         <plugins>
             <plugin>
                 <groupId>com.github.eirslett</groupId>
                 <artifactId>frontend-maven-plugin</artifactId>
-                <version>0.0.23</version>
+                <version>1.0</version>
 
                 <configuration>
-                    <workingDirectory>src/main/js</workingDirectory>
+                    <workingDirectory>frontend</workingDirectory>
                 </configuration>
 
                 <executions>
@@ -51,8 +52,9 @@
                             <goal>install-node-and-npm</goal>
                         </goals>
                         <configuration>
-                            <nodeVersion>v4.4.4</nodeVersion>
-                            <npmVersion>2.14.20</npmVersion>
+                            <nodeVersion>v4.4.7</nodeVersion>
+                            <npmVersion>3.8.6</npmVersion>
+                            <workingDirectory>frontend</workingDirectory>
                         </configuration>
                     </execution>
 
@@ -61,9 +63,32 @@
                         <goals>
                             <goal>npm</goal>
                         </goals>
+
+                        <configuration>
+                            <arguments>install --no-optional</arguments>
+                        </configuration>
+                    </execution>
+
+                    <execution>
+                        <id>gulp build</id>
+                        <goals>
+                            <goal>gulp</goal>
+                        </goals>
+
+                        <configuration>
+                            <arguments>build</arguments>
+                        </configuration>
                     </execution>
                 </executions>
             </plugin>
+
+            <plugin>
+                <groupId>org.apache.maven.plugins</groupId>
+                <artifactId>maven-deploy-plugin</artifactId>
+                <configuration>
+                    <skip>true</skip>
+                </configuration>
+            </plugin>
         </plugins>
     </build>
 </project>

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/src/main/js/.babelrc
----------------------------------------------------------------------
diff --git a/modules/web-console/src/main/js/.babelrc b/modules/web-console/src/main/js/.babelrc
deleted file mode 100644
index af0f0c3..0000000
--- a/modules/web-console/src/main/js/.babelrc
+++ /dev/null
@@ -1,3 +0,0 @@
-{
-  "presets": ["es2015"]
-}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/src/main/js/.eslintrc
----------------------------------------------------------------------
diff --git a/modules/web-console/src/main/js/.eslintrc b/modules/web-console/src/main/js/.eslintrc
deleted file mode 100644
index 1882b44..0000000
--- a/modules/web-console/src/main/js/.eslintrc
+++ /dev/null
@@ -1,202 +0,0 @@
-parser: "babel-eslint"
-
-env:
-    es6: true
-    browser: true
-
-ecmaFeatures:
-    arrowFunctions: true
-    blockBindings: true
-    classes: true
-    defaultParams: true
-    destructuring: true
-    module: true
-    objectLiteralComputedProperties: true
-    objectLiteralShorthandMethods: true
-    objectLiteralShorthandProperties: true
-    spread: true
-    templateStrings: true
-    experimentalObjectRestSpread: true
-
-globals:
-    _: true
-    $: true
-    d3: true
-    io: true
-    window: true
-    global: true
-    angular: true
-    $generatorCommon: true
-    $generatorProperties: true
-    $generatorXml: true
-    $generatorJava: true
-    $generatorPom: true
-    $generatorReadme: true
-    $generatorDocker: true
-    $generatorOptional: true
-    saveAs: true
-    process: true
-
-rules:
-    arrow-parens: [1, "always"]
-    arrow-spacing: [1, { "before": true, "after": true }]
-    accessor-pairs: 2
-    block-scoped-var: 2
-    brace-style: [0, "1tbs"]
-    comma-dangle: [2, "never"]
-    comma-spacing: [2, {"before": false, "after": true}]
-    comma-style: [2, "last"]
-    complexity: [1, 11]
-    computed-property-spacing: [2, "never"]
-    consistent-return: 0
-    consistent-this: [0, "that"]
-    constructor-super: 2
-    curly: [2, "multi-or-nest"]
-    default-case: 2
-    dot-location: 0
-    dot-notation: [2, { "allowKeywords": true }]
-    eol-last: 2
-    eqeqeq: 2
-    func-names: 0
-    func-style: [0, "declaration"]
-    generator-star-spacing: 0
-    guard-for-in: 1
-    handle-callback-err: 0
-    id-length: [2, {"min": 1, "max": 60}]
-    indent: [2, 4, {"SwitchCase": 1}]
-    key-spacing: [2, { "beforeColon": false, "afterColon": true }]
-    lines-around-comment: 0
-    linebreak-style: [0, "unix"]
-    max-depth: [0, 4]
-    max-len: [0, 120, 4]
-    max-nested-callbacks: [1, 4]
-    max-params: [0, 3]
-    max-statements: [0, 10]
-    new-cap: 2
-    new-parens: 2
-    no-alert: 2
-    no-array-constructor: 2
-    no-bitwise: 0
-    no-caller: 2
-    no-catch-shadow: 2
-    no-cond-assign: 2
-    no-console: 0
-    no-constant-condition: 2
-    no-continue: 0
-    no-class-assign: 2
-    no-const-assign: 2
-    no-control-regex: 2
-    no-debugger: 2
-    no-delete-var: 2
-    no-div-regex: 0
-    no-dupe-keys: 2
-    no-dupe-args: 2
-    no-duplicate-case: 2
-    no-else-return: 2
-    no-empty: 2
-    no-empty-character-class: 2
-    no-eq-null: 2
-    no-eval: 2
-    no-ex-assign: 2
-    no-extend-native: 2
-    no-extra-bind: 2
-    no-extra-boolean-cast: 2
-    no-extra-parens: 0
-    no-extra-semi: 2
-    no-fallthrough: 2
-    no-floating-decimal: 1
-    no-func-assign: 2
-    no-implied-eval: 2
-    no-inline-comments: 0
-    no-inner-declarations: [2, "functions"]
-    no-invalid-regexp: 2
-    no-irregular-whitespace: 2
-    no-iterator: 2
-    no-label-var: 2
-    no-labels: 2
-    no-lone-blocks: 2
-    no-lonely-if: 2
-    no-implicit-coercion: [2, {"boolean": false, "number": true, "string": true}]
-    no-loop-func: 2
-    no-mixed-requires: [0, false]
-    no-mixed-spaces-and-tabs: [2, true]
-    no-multi-spaces: 2
-    no-multi-str: 2
-    no-multiple-empty-lines: [0, {"max": 2}]
-    no-native-reassign: 2
-    no-negated-in-lhs: 2
-    no-nested-ternary: 0
-    no-new: 2
-    no-new-func: 2
-    no-new-object: 2
-    no-new-require: 0
-    no-new-wrappers: 2
-    no-obj-calls: 2
-    no-octal: 2
-    no-octal-escape: 2
-    no-param-reassign: 0
-    no-path-concat: 0
-    no-plusplus: 0
-    no-process-env: 0
-    no-process-exit: 2
-    no-proto: 2
-    no-redeclare: 2
-    no-regex-spaces: 1
-    no-restricted-modules: 0
-    no-script-url: 0
-    no-self-compare: 2
-    no-sequences: 2
-    no-shadow: 2
-    no-shadow-restricted-names: 2
-    no-spaced-func: 2
-    no-sparse-arrays: 1
-    no-sync: 0
-    no-ternary: 0
-    no-trailing-spaces: 2
-    no-throw-literal: 0
-    no-this-before-super: 2
-    no-unexpected-multiline: 2
-    no-undef: 2
-    no-undef-init: 2
-    no-undefined: 2
-    no-unneeded-ternary: 2
-    no-unreachable: 2
-    no-unused-expressions: [2, { allowShortCircuit: true }]
-    no-unused-vars: [2, {"vars": "all", "args": "after-used"}]
-    no-use-before-define: 2
-    no-useless-call: 2
-    no-void: 0
-    no-var: 2
-    no-warning-comments: 0
-    no-with: 2
-    newline-after-var: 0
-    object-shorthand: [2, "always"]
-    one-var: [2, "never"]
-    operator-assignment: [2, "always"]
-    operator-linebreak: 0
-    padded-blocks: 0
-    prefer-const: 1
-    prefer-spread: 2
-    quote-props: [2, "as-needed"]
-    quotes: [2, "single"]
-    radix: 1
-    semi: [2, "always"]
-    semi-spacing: [2, {"before": false, "after": true}]
-    sort-vars: 0
-    keyword-spacing: 2
-    space-before-blocks: [2, "always"]
-    space-before-function-paren: [2, "never"]
-    space-in-parens: 0
-    space-infix-ops: 2
-    space-unary-ops: [2, { "words": true, "nonwords": false }]
-    spaced-comment: [1, "always"]
-    use-isnan: 2
-    valid-jsdoc: 0
-    valid-typeof: 2
-    vars-on-top: 2
-    wrap-iife: 0
-    wrap-regex: 0
-    yoda: [2, "never"]
-
-parserOptions:
-    sourceType: module

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/src/main/js/.gitignore
----------------------------------------------------------------------
diff --git a/modules/web-console/src/main/js/.gitignore b/modules/web-console/src/main/js/.gitignore
deleted file mode 100644
index a6af5e1..0000000
--- a/modules/web-console/src/main/js/.gitignore
+++ /dev/null
@@ -1,9 +0,0 @@
-*.idea
-*.log
-.npmrc
-build/*
-node_modules
-ignite_modules_temp/*
-public/stylesheets/*.css
-serve/config/*.json
-serve/agent_dists/*.zip

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/src/main/js/app/app.config.js
----------------------------------------------------------------------
diff --git a/modules/web-console/src/main/js/app/app.config.js b/modules/web-console/src/main/js/app/app.config.js
deleted file mode 100644
index 25c24b0..0000000
--- a/modules/web-console/src/main/js/app/app.config.js
+++ /dev/null
@@ -1,86 +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 alertTemplateUrl from '../views/templates/alert.jade';
-
-const igniteConsoleCfg = angular.module('ignite-console.config', ['ngAnimate', 'mgcrea.ngStrap']);
-
-// Configure AngularJS animation: do not animate fa-spin.
-igniteConsoleCfg.config(['$animateProvider', ($animateProvider) => {
-    $animateProvider.classNameFilter(/^((?!(fa-spin)).)*$/);
-}]);
-
-// AngularStrap modal popup configuration.
-igniteConsoleCfg.config(['$modalProvider', ($modalProvider) => {
-    angular.extend($modalProvider.defaults, {
-        animation: 'am-fade-and-scale',
-        html: true
-    });
-}]);
-
-// AngularStrap popover configuration.
-igniteConsoleCfg.config(['$popoverProvider', ($popoverProvider) => {
-    angular.extend($popoverProvider.defaults, {
-        trigger: 'manual',
-        placement: 'right',
-        container: 'body',
-        templateUrl: '/templates/validation-error.html'
-    });
-}]);
-
-// AngularStrap tooltips configuration.
-igniteConsoleCfg.config(['$tooltipProvider', ($tooltipProvider) => {
-    angular.extend($tooltipProvider.defaults, {
-        container: 'body',
-        delay: 150,
-        placement: 'right',
-        html: 'true',
-        trigger: 'click hover'
-    });
-}]);
-
-// AngularStrap select (combobox) configuration.
-igniteConsoleCfg.config(['$selectProvider', ($selectProvider) => {
-    angular.extend($selectProvider.defaults, {
-        container: 'body',
-        maxLength: '5',
-        allText: 'Select All',
-        noneText: 'Clear All',
-        templateUrl: '/templates/select.html',
-        iconCheckmark: 'fa fa-check',
-        caretHtml: ''
-    });
-}]);
-
-// AngularStrap alerts configuration.
-igniteConsoleCfg.config(['$alertProvider', ($alertProvider) => {
-    angular.extend($alertProvider.defaults, {
-        container: 'body',
-        placement: 'top-right',
-        duration: '5',
-        templateUrl: alertTemplateUrl,
-        type: 'danger'
-    });
-}]);
-
-
-// AngularStrap dropdowns () configuration.
-igniteConsoleCfg.config(['$dropdownProvider', ($dropdownProvider) => {
-    angular.extend($dropdownProvider.defaults, {
-        templateUrl: 'templates/dropdown.html'
-    });
-}]);

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/src/main/js/app/app.js
----------------------------------------------------------------------
diff --git a/modules/web-console/src/main/js/app/app.js b/modules/web-console/src/main/js/app/app.js
deleted file mode 100644
index 00ae3eb..0000000
--- a/modules/web-console/src/main/js/app/app.js
+++ /dev/null
@@ -1,274 +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 '../public/stylesheets/style.scss';
-
-import './app.config';
-
-import './decorator/select';
-import './decorator/tooltip';
-
-import './modules/form/form.module';
-import './modules/agent/agent.module.js';
-import './modules/query-notebooks/query-notebooks.module';
-import './modules/Demo/Demo.module.js';
-
-import './modules/states/signin.state';
-import './modules/states/logout.state';
-import './modules/states/password.state';
-import './modules/states/configuration.state';
-import './modules/states/sql.state';
-import './modules/states/profile.state';
-import './modules/states/admin.state';
-
-// ignite:modules
-import './modules/user/user.module';
-import './modules/branding/branding.module';
-import './modules/navbar/navbar.module';
-import './modules/configuration/configuration.module';
-import './modules/getting-started/GettingStarted.provider';
-import './modules/dialog/dialog.module';
-import './modules/Version/Version.provider';
-import './modules/ace.module';
-import './modules/socket.module';
-import './modules/loading/loading.module';
-// endignite
-
-// Directives.
-import igniteAutoFocus from './directives/auto-focus.directive.js';
-import igniteBsAffixUpdate from './directives/bs-affix-update.directive';
-import igniteCentered from './directives/centered/centered.directive.js';
-import igniteCopyToClipboard from './directives/copy-to-clipboard.directive.js';
-import igniteHideOnStateChange from './directives/hide-on-state-change/hide-on-state-change.directive';
-import igniteInformation from './directives/information/information.directive';
-import igniteMatch from './directives/match.directive.js';
-import igniteOnClickFocus from './directives/on-click-focus.directive.js';
-import igniteOnEnter from './directives/on-enter.directive.js';
-import igniteOnEnterFocusMove from './directives/on-enter-focus-move.directive.js';
-import igniteOnEscape from './directives/on-escape.directive.js';
-import igniteUiAceDocker from './directives/ui-ace-docker/ui-ace-docker.directive';
-import igniteUiAceJava from './directives/ui-ace-java/ui-ace-java.directive';
-import igniteUiAcePojos from './directives/ui-ace-pojos/ui-ace-pojos.directive';
-import igniteUiAcePom from './directives/ui-ace-pom/ui-ace-pom.directive';
-import igniteUiAceTabs from './directives/ui-ace-tabs.directive';
-import igniteUiAceXml from './directives/ui-ace-xml/ui-ace-xml.directive';
-
-// Services.
-import ChartColors from './services/ChartColors.service';
-import Clone from './services/Clone.service.js';
-import Confirm from './services/Confirm.service.js';
-import ConfirmBatch from './services/ConfirmBatch.service.js';
-import CopyToClipboard from './services/CopyToClipboard.service';
-import Countries from './services/Countries.service';
-import Focus from './services/Focus.service';
-import InetAddress from './services/InetAddress.service';
-import JavaTypes from './services/JavaTypes.service';
-import Messages from './services/Messages.service';
-import ModelNormalizer from './services/ModelNormalizer.service.js';
-import LegacyTable from './services/LegacyTable.service';
-import LegacyUtils from './services/LegacyUtils.service';
-import UnsavedChangesGuard from './services/UnsavedChangesGuard.service';
-
-// Providers.
-
-// Filters.
-import byName from './filters/byName.filter';
-import domainsValidation from './filters/domainsValidation.filter';
-import hasPojo from './filters/hasPojo.filter';
-
-// Generators
-import $generatorCommon from 'generator/generator-common';
-import $generatorJava from 'generator/generator-java';
-import $generatorOptional from 'generator/generator-optional';
-import $generatorProperties from 'generator/generator-properties';
-import $generatorReadme from 'generator/generator-readme';
-import $generatorXml from 'generator/generator-xml';
-
-window.$generatorCommon = $generatorCommon;
-window.$generatorJava = $generatorJava;
-window.$generatorOptional = $generatorOptional;
-window.$generatorProperties = $generatorProperties;
-window.$generatorReadme = $generatorReadme;
-window.$generatorXml = $generatorXml;
-
-// Controllers
-import admin from 'controllers/admin-controller';
-import caches from 'controllers/caches-controller';
-import clusters from 'controllers/clusters-controller';
-import domains from 'controllers/domains-controller';
-import igfs from 'controllers/igfs-controller';
-import profile from 'controllers/profile-controller';
-import sql from 'controllers/sql-controller';
-import auth from './controllers/auth.controller';
-import notebooks from './controllers/notebooks.controller';
-import resetPassword from './controllers/reset-password.controller';
-
-// Inject external modules.
-import 'ignite_modules_temp/index';
-
-import baseTemplate from '../views/base.jade';
-
-angular
-.module('ignite-console', [
-    // Optional AngularJS modules.
-    'ngAnimate',
-    'ngSanitize',
-    // Third party libs.
-    'ngRetina',
-    'btford.socket-io',
-    'mgcrea.ngStrap',
-    'ui.router',
-    'gridster',
-    'dndLists',
-    'nvd3',
-    'smart-table',
-    'treeControl',
-    'ui.grid',
-    'ui.grid.saveState',
-    'ui.grid.selection',
-    'ui.grid.resizeColumns',
-    'ui.grid.autoResize',
-    'ui.grid.exporter',
-    // Base modules.
-    'ignite-console.ace',
-    'ignite-console.Form',
-    'ignite-console.user',
-    'ignite-console.branding',
-    'ignite-console.socket',
-    'ignite-console.agent',
-    'ignite-console.query-notebooks',
-    'ignite-console.demo',
-    // States.
-    'ignite-console.states.login',
-    'ignite-console.states.logout',
-    'ignite-console.states.password',
-    'ignite-console.states.configuration',
-    'ignite-console.states.sql',
-    'ignite-console.states.profile',
-    'ignite-console.states.admin',
-    // Common modules.
-    'ignite-console.dialog',
-    'ignite-console.navbar',
-    'ignite-console.configuration',
-    'ignite-console.getting-started',
-    'ignite-console.version',
-    'ignite-console.loading',
-    // Ignite configuration module.
-    'ignite-console.config',
-    // Ignite modules.
-    'ignite-console.modules'
-])
-// Directives.
-.directive(...igniteAutoFocus)
-.directive(...igniteBsAffixUpdate)
-.directive(...igniteCentered)
-.directive(...igniteCopyToClipboard)
-.directive(...igniteHideOnStateChange)
-.directive(...igniteInformation)
-.directive(...igniteMatch)
-.directive(...igniteOnClickFocus)
-.directive(...igniteOnEnter)
-.directive(...igniteOnEnterFocusMove)
-.directive(...igniteOnEscape)
-.directive(...igniteUiAceDocker)
-.directive(...igniteUiAceJava)
-.directive(...igniteUiAcePojos)
-.directive(...igniteUiAcePom)
-.directive(...igniteUiAceTabs)
-.directive(...igniteUiAceXml)
-// Services.
-.service(...ChartColors)
-.service(...Clone)
-.service(...Confirm)
-.service(...ConfirmBatch)
-.service(...CopyToClipboard)
-.service(...Countries)
-.service(...Focus)
-.service(...InetAddress)
-.service(...JavaTypes)
-.service(...Messages)
-.service(...ModelNormalizer)
-.service(...LegacyTable)
-.service(...LegacyUtils)
-.service(...UnsavedChangesGuard)
-// Controllers.
-.controller(...admin)
-.controller(...auth)
-.controller(...notebooks)
-.controller(...resetPassword)
-.controller(...caches)
-.controller(...clusters)
-.controller(...domains)
-.controller(...igfs)
-.controller(...profile)
-.controller(...sql)
-// Filters.
-.filter(...hasPojo)
-.filter(...domainsValidation)
-.filter(...byName)
-.config(['$stateProvider', '$locationProvider', '$urlRouterProvider', ($stateProvider, $locationProvider, $urlRouterProvider) => {
-    // Set up the states.
-    $stateProvider
-        .state('base', {
-            url: '',
-            abstract: true,
-            templateUrl: baseTemplate
-        })
-        .state('settings', {
-            url: '/settings',
-            abstract: true,
-            templateUrl: baseTemplate
-        });
-
-    $urlRouterProvider.otherwise('/');
-
-    $locationProvider.html5Mode(true);
-}])
-.run(['$rootScope', '$state', 'MetaTags', 'gettingStarted', ($root, $state, $meta, gettingStarted) => {
-    $root._ = _;
-    $root.$state = $state;
-    $root.$meta = $meta;
-    $root.gettingStarted = gettingStarted;
-}])
-.run(['$rootScope', 'Auth', 'User', 'IgniteAgentMonitor', ($root, Auth, User, agentMonitor) => {
-    if (Auth.authorized) {
-        User.read()
-            .then((user) => $root.$broadcast('user', user))
-            .then(() => Auth.authorized && agentMonitor.init());
-    }
-}])
-.run(['$rootScope', ($root) => {
-    $root.$on('$stateChangeStart', () => {
-        _.forEach(angular.element('.modal'), (m) => angular.element(m).scope().$hide());
-    });
-}])
-.run(['$rootScope', '$http', '$state', 'IgniteMessages', 'User',
-    ($root, $http, $state, Messages, User) => { // eslint-disable-line no-shadow
-        $root.revertIdentity = () => {
-            $http
-                .get('/api/v1/admin/revert/identity')
-                .then(User.read)
-                .then((user) => {
-                    $root.$broadcast('user', user);
-
-                    $state.go('settings.admin');
-                })
-                .catch(Messages.showError);
-        };
-    }
-]);
-

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/src/main/js/app/controllers/auth.controller.js
----------------------------------------------------------------------
diff --git a/modules/web-console/src/main/js/app/controllers/auth.controller.js b/modules/web-console/src/main/js/app/controllers/auth.controller.js
deleted file mode 100644
index 21ffeb8..0000000
--- a/modules/web-console/src/main/js/app/controllers/auth.controller.js
+++ /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.
- */
-
-// Sign in controller.
-// TODO IGNITE-1936 Refactor this controller.
-export default ['auth', [
-    '$scope', 'IgniteFocus', 'IgniteCountries', 'Auth',
-    ($scope, Focus, Countries, Auth) => {
-        $scope.auth = Auth.auth;
-        $scope.forgotPassword = Auth.forgotPassword;
-        $scope.action = 'signin';
-        $scope.countries = Countries.getAll();
-
-        Focus.move('user_email');
-    }
-]];

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/src/main/js/app/controllers/notebooks.controller.js
----------------------------------------------------------------------
diff --git a/modules/web-console/src/main/js/app/controllers/notebooks.controller.js b/modules/web-console/src/main/js/app/controllers/notebooks.controller.js
deleted file mode 100644
index 0440c46..0000000
--- a/modules/web-console/src/main/js/app/controllers/notebooks.controller.js
+++ /dev/null
@@ -1,69 +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.
- */
-
-// Controller that load notebooks in navigation bar .
-export default ['notebooks', [
-    '$rootScope', '$scope', '$modal', '$state', '$http', 'IgniteMessages',
-    ($root, $scope, $modal, $state, $http, Messages) => {
-        $root.notebooks = [];
-
-        // Pre-fetch modal dialogs.
-        const _notebookNewModal = $modal({scope: $scope, templateUrl: '/sql/notebook-new.html', show: false});
-
-        $root.rebuildDropdown = function() {
-            $scope.notebookDropdown = [
-                {text: 'Create new notebook', click: 'inputNotebookName()'},
-                {divider: true}
-            ];
-
-            _.forEach($root.notebooks, (notebook) => $scope.notebookDropdown.push({
-                text: notebook.name,
-                sref: 'base.sql.notebook({noteId:"' + notebook._id + '"})'
-            }));
-        };
-
-        $root.reloadNotebooks = function() {
-            // When landing on the page, get clusters and show them.
-            $http.post('/api/v1/notebooks/list')
-                .success((data) => {
-                    $root.notebooks = data;
-
-                    $root.rebuildDropdown();
-                })
-                .error(Messages.showError);
-        };
-
-        $root.inputNotebookName = () => {
-            _notebookNewModal.$promise.then(_notebookNewModal.show);
-        };
-
-        $root.createNewNotebook = (name) => {
-            $http.post('/api/v1/notebooks/new', {name})
-                .success((noteId) => {
-                    _notebookNewModal.hide();
-
-                    $root.reloadNotebooks();
-
-                    $state.go('base.sql.notebook', {noteId});
-                })
-                .error(Messages.showError);
-        };
-
-        $root.reloadNotebooks();
-
-    }
-]];

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/src/main/js/app/controllers/reset-password.controller.js
----------------------------------------------------------------------
diff --git a/modules/web-console/src/main/js/app/controllers/reset-password.controller.js b/modules/web-console/src/main/js/app/controllers/reset-password.controller.js
deleted file mode 100644
index f3cee81..0000000
--- a/modules/web-console/src/main/js/app/controllers/reset-password.controller.js
+++ /dev/null
@@ -1,51 +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.
- */
-
-// Controller for password reset.
-export default ['resetPassword', [
-    '$scope', '$modal', '$http', '$state', 'IgniteMessages', 'IgniteFocus',
-    ($scope, $modal, $http, $state, Messages, Focus) => {
-        if ($state.params.token) {
-            $http.post('/api/v1/password/validate/token', {token: $state.params.token})
-                .success((res) => {
-                    $scope.email = res.email;
-                    $scope.token = res.token;
-                    $scope.error = res.error;
-
-                    if ($scope.token && !$scope.error)
-                        Focus.move('user_password');
-                });
-        }
-
-        // Try to reset user password for provided token.
-        $scope.resetPassword = (reset_info) => {
-            $http.post('/api/v1/password/reset', reset_info)
-                .success(() => {
-                    Messages.showInfo('Password successfully changed');
-
-                    $state.go('base.configuration.clusters');
-                })
-                .error((err, state) => {
-                    Messages.showError(err);
-
-                    if (state === 503)
-                        $state.go('base.configuration.clusters');
-                });
-        };
-
-    }
-]];

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/src/main/js/app/data/colors.json
----------------------------------------------------------------------
diff --git a/modules/web-console/src/main/js/app/data/colors.json b/modules/web-console/src/main/js/app/data/colors.json
deleted file mode 100644
index 188e485..0000000
--- a/modules/web-console/src/main/js/app/data/colors.json
+++ /dev/null
@@ -1,22 +0,0 @@
-[
-  "#1f77b4",
-  "#ff7f0e",
-  "#2ca02c",
-  "#d62728",
-  "#9467bd",
-  "#8c564b",
-  "#e377c2",
-  "#7f7f7f",
-  "#bcbd22",
-  "#17becf",
-  "#ffbb78",
-  "#98df8a",
-  "#ff9896",
-  "#c5b0d5",
-  "#aec7e8",
-  "#c49c94",
-  "#f7b6d2",
-  "#c7c7c7",
-  "#dbdb8d",
-  "#9edae5"
-]

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/src/main/js/app/data/countries.json
----------------------------------------------------------------------
diff --git a/modules/web-console/src/main/js/app/data/countries.json b/modules/web-console/src/main/js/app/data/countries.json
deleted file mode 100644
index f420f48..0000000
--- a/modules/web-console/src/main/js/app/data/countries.json
+++ /dev/null
@@ -1,94 +0,0 @@
-[
-  {
-    "name": "United States",
-    "code": "USA"
-  },
-  {
-    "name": "Canada",
-    "code": "CAN"
-  },
-  {
-    "name": "United Kingdom",
-    "code": "GBR"
-  },
-  {
-    "name": "Germany",
-    "code": "DEU"
-  },
-  {
-    "name": "France",
-    "code": "FRA"
-  },
-  {
-    "name": "Switzerland",
-    "code": "CHE"
-  },
-  {
-    "name": "Netherlands",
-    "code": "NLD"
-  },
-  {
-    "name": "Israel",
-    "code": "ISR"
-  },
-  {
-    "name": "Sweden",
-    "code": "SWE"
-  },
-  {
-    "name": "Russia",
-    "code": "RUS"
-  },
-  {
-    "name": "Other Europe",
-    "code": "Other Europe"
-  },
-  {
-    "name": "China",
-    "code": "CHN"
-  },
-  {
-    "name": "India",
-    "code": "IND"
-  },
-  {
-    "name": "Japan",
-    "code": "JPN"
-  },
-  {
-    "name": "Other Asia",
-    "code": "Other Asia"
-  },
-  {
-    "name": "Australia",
-    "code": "AUS"
-  },
-  {
-    "name": "Brazil",
-    "code": "BRA"
-  },
-  {
-    "name": "Argentina",
-    "code": "ARG"
-  },
-  {
-    "name": "Other South America",
-    "code": "Other South America"
-  },
-  {
-    "name": "South Africa",
-    "code": "ZAF"
-  },
-  {
-    "name": "Nigeria",
-    "code": "NGA"
-  },
-  {
-    "name": "Other Africa",
-    "code": "Other Africa"
-  },
-  {
-    "name": "Rest of the World",
-    "code": "Rest of the World"
-  }
-]

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/src/main/js/app/data/demo-info.json
----------------------------------------------------------------------
diff --git a/modules/web-console/src/main/js/app/data/demo-info.json b/modules/web-console/src/main/js/app/data/demo-info.json
deleted file mode 100644
index 0d2ad22..0000000
--- a/modules/web-console/src/main/js/app/data/demo-info.json
+++ /dev/null
@@ -1,14 +0,0 @@
-[
-    {
-        "title": "Apache Ignite Web Console Demo",
-        "message": [
-            "<div>",
-            " <h4><i class='fa fa-cogs fa-cursor-default'></i>&nbsp;What Can You Do</h4>",
-            " <ul>",
-            "  <li><b>Configuration</b> to checkout predefined clusters, caches, domain models and IGFS</li>",
-            "  <li><b>SQL</b> to run various SQL queries on the demo database</li>",
-            " </ul>",
-            "</div>"
-        ]
-    }
-]

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/src/main/js/app/data/event-types.json
----------------------------------------------------------------------
diff --git a/modules/web-console/src/main/js/app/data/event-types.json b/modules/web-console/src/main/js/app/data/event-types.json
deleted file mode 100644
index 8d0c878..0000000
--- a/modules/web-console/src/main/js/app/data/event-types.json
+++ /dev/null
@@ -1,169 +0,0 @@
-[
-  {
-    "label": "EVTS_CHECKPOINT",
-    "value": "EVTS_CHECKPOINT",
-    "class": "org.apache.ignite.events.EventType",
-    "events": [
-      "EVT_CHECKPOINT_SAVED",
-      "EVT_CHECKPOINT_LOADED",
-      "EVT_CHECKPOINT_REMOVED"
-    ]
-  },
-  {
-    "label": "EVTS_DEPLOYMENT",
-    "value": "EVTS_DEPLOYMENT",
-    "class": "org.apache.ignite.events.EventType",
-    "events": [
-      "EVT_CLASS_DEPLOYED",
-      "EVT_CLASS_UNDEPLOYED",
-      "EVT_CLASS_DEPLOY_FAILED",
-      "EVT_TASK_DEPLOYED",
-      "EVT_TASK_UNDEPLOYED",
-      "EVT_TASK_DEPLOY_FAILED"
-    ]
-  },
-  {
-    "label": "EVTS_ERROR",
-    "value": "EVTS_ERROR",
-    "class": "org.apache.ignite.events.EventType",
-    "events": [
-      "EVT_JOB_TIMEDOUT",
-      "EVT_JOB_FAILED",
-      "EVT_JOB_FAILED_OVER",
-      "EVT_JOB_REJECTED",
-      "EVT_JOB_CANCELLED",
-      "EVT_TASK_TIMEDOUT",
-      "EVT_TASK_FAILED",
-      "EVT_CLASS_DEPLOY_FAILED",
-      "EVT_TASK_DEPLOY_FAILED",
-      "EVT_TASK_DEPLOYED",
-      "EVT_TASK_UNDEPLOYED",
-      "EVT_CACHE_REBALANCE_STARTED",
-      "EVT_CACHE_REBALANCE_STOPPED"
-    ]
-  },
-  {
-    "label": "EVTS_DISCOVERY",
-    "value": "EVTS_DISCOVERY",
-    "class": "org.apache.ignite.events.EventType",
-    "events": [
-      "EVT_NODE_JOINED",
-      "EVT_NODE_LEFT",
-      "EVT_NODE_FAILED",
-      "EVT_NODE_SEGMENTED",
-      "EVT_CLIENT_NODE_DISCONNECTED",
-      "EVT_CLIENT_NODE_RECONNECTED"
-    ]
-  },
-  {
-    "label": "EVTS_JOB_EXECUTION",
-    "value": "EVTS_JOB_EXECUTION",
-    "class": "org.apache.ignite.events.EventType",
-    "events": [
-      "EVT_JOB_MAPPED",
-      "EVT_JOB_RESULTED",
-      "EVT_JOB_FAILED_OVER",
-      "EVT_JOB_STARTED",
-      "EVT_JOB_FINISHED",
-      "EVT_JOB_TIMEDOUT",
-      "EVT_JOB_REJECTED",
-      "EVT_JOB_FAILED",
-      "EVT_JOB_QUEUED",
-      "EVT_JOB_CANCELLED"
-    ]
-  },
-  {
-    "label": "EVTS_TASK_EXECUTION",
-    "value": "EVTS_TASK_EXECUTION",
-    "class": "org.apache.ignite.events.EventType",
-    "events": [
-      "EVT_TASK_STARTED",
-      "EVT_TASK_FINISHED",
-      "EVT_TASK_FAILED",
-      "EVT_TASK_TIMEDOUT",
-      "EVT_TASK_SESSION_ATTR_SET",
-      "EVT_TASK_REDUCED"
-    ]
-  },
-  {
-    "label": "EVTS_CACHE",
-    "value": "EVTS_CACHE",
-    "class": "org.apache.ignite.events.EventType",
-    "events": [
-      "EVT_CACHE_ENTRY_CREATED",
-      "EVT_CACHE_ENTRY_DESTROYED",
-      "EVT_CACHE_OBJECT_PUT",
-      "EVT_CACHE_OBJECT_READ",
-      "EVT_CACHE_OBJECT_REMOVED",
-      "EVT_CACHE_OBJECT_LOCKED",
-      "EVT_CACHE_OBJECT_UNLOCKED",
-      "EVT_CACHE_OBJECT_SWAPPED",
-      "EVT_CACHE_OBJECT_UNSWAPPED",
-      "EVT_CACHE_OBJECT_EXPIRED"
-    ]
-  },
-  {
-    "label": "EVTS_CACHE_REBALANCE",
-    "value": "EVTS_CACHE_REBALANCE",
-    "class": "org.apache.ignite.events.EventType",
-    "events": [
-      "EVT_CACHE_REBALANCE_STARTED",
-      "EVT_CACHE_REBALANCE_STOPPED",
-      "EVT_CACHE_REBALANCE_PART_LOADED",
-      "EVT_CACHE_REBALANCE_PART_UNLOADED",
-      "EVT_CACHE_REBALANCE_OBJECT_LOADED",
-      "EVT_CACHE_REBALANCE_OBJECT_UNLOADED",
-      "EVT_CACHE_REBALANCE_PART_DATA_LOST"
-    ]
-  },
-  {
-    "label": "EVTS_CACHE_LIFECYCLE",
-    "value": "EVTS_CACHE_LIFECYCLE",
-    "class": "org.apache.ignite.events.EventType",
-    "events": [
-      "EVT_CACHE_STARTED",
-      "EVT_CACHE_STOPPED",
-      "EVT_CACHE_NODES_LEFT"
-    ]
-  },
-  {
-    "label": "EVTS_CACHE_QUERY",
-    "value": "EVTS_CACHE_QUERY",
-    "class": "org.apache.ignite.events.EventType",
-    "events": [
-      "EVT_CACHE_QUERY_EXECUTED",
-      "EVT_CACHE_QUERY_OBJECT_READ"
-    ]
-  },
-  {
-    "label": "EVTS_SWAPSPACE",
-    "value": "EVTS_SWAPSPACE",
-    "class": "org.apache.ignite.events.EventType",
-    "events": [
-      "EVT_SWAP_SPACE_CLEARED",
-      "EVT_SWAP_SPACE_DATA_REMOVED",
-      "EVT_SWAP_SPACE_DATA_READ",
-      "EVT_SWAP_SPACE_DATA_STORED",
-      "EVT_SWAP_SPACE_DATA_EVICTED"
-    ]
-  },
-  {
-    "label": "EVTS_IGFS",
-    "value": "EVTS_IGFS",
-    "class": "org.apache.ignite.events.EventType",
-    "events": [
-      "EVT_IGFS_FILE_CREATED",
-      "EVT_IGFS_FILE_RENAMED",
-      "EVT_IGFS_FILE_DELETED",
-      "EVT_IGFS_FILE_OPENED_READ",
-      "EVT_IGFS_FILE_OPENED_WRITE",
-      "EVT_IGFS_FILE_CLOSED_WRITE",
-      "EVT_IGFS_FILE_CLOSED_READ",
-      "EVT_IGFS_FILE_PURGED",
-      "EVT_IGFS_META_UPDATED",
-      "EVT_IGFS_DIR_CREATED",
-      "EVT_IGFS_DIR_RENAMED",
-      "EVT_IGFS_DIR_DELETED"
-    ]
-  }
-]

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/src/main/js/app/data/getting-started.json
----------------------------------------------------------------------
diff --git a/modules/web-console/src/main/js/app/data/getting-started.json b/modules/web-console/src/main/js/app/data/getting-started.json
deleted file mode 100644
index 1b435ab..0000000
--- a/modules/web-console/src/main/js/app/data/getting-started.json
+++ /dev/null
@@ -1,109 +0,0 @@
-[
-    {
-        "title": "With Apache Ignite Web Console You Can",
-        "message": [
-            "<div class='col-xs-4'>",
-            " <img src='/images/ignite-puzzle.png' width='80%' class='getting-started-puzzle' />",
-            "</div>",
-            "<div class='col-xs-8'>",
-            " <ul>",
-            "  <li>Generate cluster configuration</li>",
-            "  <li>Import domain model from database</li>",
-            "  <li>Configure all needed caches</li>",
-            "  <li>Preview generated XML and Java code in browser</li>",
-            "  <li>Download ready-to-use Maven project</li>",
-            "  <li>Execute SQL queries on real clusters</li>",
-            " </ul>",
-            "</div>"
-        ]
-    },
-    {
-        "title": "Clusters",
-        "message": [
-            "<div class='col-xs-7'>",
-            " <img src='/images/cluster.png' width='100%' />",
-            "</div>",
-            "<div class='col-xs-5'>",
-            " <ul>",
-            "  <li>Configure cluster properties</li>",
-            "  <li>Associate cluster with caches</li>",
-            " </ul>",
-            "</div>"
-        ]
-    },
-    {
-        "title": "Domain Model",
-        "message": [
-            "<div class='col-xs-7'>",
-            " <img src='/images/domains.png' width='100%' />",
-            "</div>",
-            "<div class='col-xs-5'>",
-            " <ul>",
-            "  <li>Import database schemas</li>",
-            "  <li>Try in <span class='getting-started-demo'>Demo</span> mode</li>",
-            " </ul>",
-            "</div>"
-        ]
-    },
-    {
-        "title": "Caches",
-        "message": [
-            "<div class='col-xs-7'>",
-            " <img src='/images/cache.png' width='100%' />",
-            "</div>",
-            "<div class='col-xs-5'>",
-            " <ul>",
-            "  <li>Configure memory settings</li>",
-            "  <li>Configure persistence</li>",
-            " </ul>",
-            "</div>"
-        ]
-    },
-    {
-        "title": "In-memory File System",
-        "message": [
-            "<div class='col-xs-7'>",
-            " <img src='/images/igfs.png' width='100%' />",
-            "</div>",
-            "<div class='col-xs-5'>",
-            " <ul>",
-            "  <li>Configure IGFS properties</li>",
-            "  <li>Associate IGFS with clusters</li>",
-            " </ul>",
-            "</div>"
-        ]
-    },
-    {
-      "title": "Summary",
-      "message": [
-          "<div class='col-xs-7'>",
-          " <img src='/images/summary.png' width='100%' />",
-          "</div>",
-          "<div class='col-xs-5'>",
-          " <ul>",
-          "  <li>Preview XML configuration</li>",
-          "  <li>Preview code configuration</li>",
-          "  <li>Preview Docker file</li>",
-          "  <li>Preview POM dependencies</li>",
-          "  <li>Download ready-to-use project</li>",
-          " </ul>",
-          "</div>"
-      ]
-    },
-    {
-        "title": "SQL Queries",
-        "message": [
-            "<div class='col-xs-7'>",
-            " <img src='/images/query-table.png' width='100%' />",
-            "</div>",
-            "<div class='col-xs-5'>",
-            " <ul>",
-            "  <li>Execute SQL Queries</li>",
-            "  <li>View Execution Paln</li>",
-            "  <li>View In-Memory Schema</li>",
-            "  <li>View Streaming Charts</li>",
-            " </ul>",
-            "</div>"
-        ]
-    }
-]

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/src/main/js/app/data/java-classes.json
----------------------------------------------------------------------
diff --git a/modules/web-console/src/main/js/app/data/java-classes.json b/modules/web-console/src/main/js/app/data/java-classes.json
deleted file mode 100644
index e2cdff9..0000000
--- a/modules/web-console/src/main/js/app/data/java-classes.json
+++ /dev/null
@@ -1,18 +0,0 @@
-[
-  {"short": "BigDecimal", "full": "java.math.BigDecimal"},
-  {"short": "Boolean", "full": "java.lang.Boolean"},
-  {"short": "Byte", "full": "java.lang.Byte"},
-  {"short": "Character", "full": "java.lang.Character"},
-  {"short": "Date", "full": "java.sql.Date"},
-  {"short": "Double", "full": "java.lang.Double"},
-  {"short": "Float", "full": "java.lang.Float"},
-  {"short": "Integer", "full": "java.lang.Integer"},
-  {"short": "Long", "full": "java.lang.Long"},
-  {"short": "Number", "full": "java.lang.Number"},
-  {"short": "Object", "full": "java.lang.Object"},
-  {"short": "Short", "full": "java.lang.Short"},
-  {"short": "String", "full": "java.lang.String"},
-  {"short": "Time", "full": "java.sql.Time"},
-  {"short": "Timestamp", "full": "java.sql.Timestamp"},
-  {"short": "UUID", "full": "java.util.UUID"}
-]

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/src/main/js/app/data/java-keywords.json
----------------------------------------------------------------------
diff --git a/modules/web-console/src/main/js/app/data/java-keywords.json b/modules/web-console/src/main/js/app/data/java-keywords.json
deleted file mode 100644
index a2d5ec2..0000000
--- a/modules/web-console/src/main/js/app/data/java-keywords.json
+++ /dev/null
@@ -1,55 +0,0 @@
-[
-  "abstract",
-  "assert",
-  "boolean",
-  "break",
-  "byte",
-  "case",
-  "catch",
-  "char",
-  "class",
-  "const",
-  "continue",
-  "default",
-  "do",
-  "double",
-  "else",
-  "enum",
-  "extends",
-  "false",
-  "final",
-  "finally",
-  "float",
-  "for",
-  "goto",
-  "if",
-  "implements",
-  "import",
-  "instanceof",
-  "int",
-  "interface",
-  "long",
-  "native",
-  "new",
-  "null",
-  "package",
-  "private",
-  "protected",
-  "public",
-  "return",
-  "short",
-  "static",
-  "strictfp",
-  "super",
-  "switch",
-  "synchronized",
-  "this",
-  "throw",
-  "throws",
-  "transient",
-  "true",
-  "try",
-  "void",
-  "volatile",
-  "while"
-]

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/src/main/js/app/data/java-primitives.json
----------------------------------------------------------------------
diff --git a/modules/web-console/src/main/js/app/data/java-primitives.json b/modules/web-console/src/main/js/app/data/java-primitives.json
deleted file mode 100644
index eab6b69..0000000
--- a/modules/web-console/src/main/js/app/data/java-primitives.json
+++ /dev/null
@@ -1,9 +0,0 @@
-[
-  "boolean",
-  "byte",
-  "double",
-  "float",
-  "int",
-  "long",
-  "short"
-]

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/src/main/js/app/data/pom-dependencies.json
----------------------------------------------------------------------
diff --git a/modules/web-console/src/main/js/app/data/pom-dependencies.json b/modules/web-console/src/main/js/app/data/pom-dependencies.json
deleted file mode 100644
index 7ab6c1b..0000000
--- a/modules/web-console/src/main/js/app/data/pom-dependencies.json
+++ /dev/null
@@ -1,20 +0,0 @@
-{
-    "Cloud": {"artifactId": "ignite-cloud"},
-    "S3": {"artifactId": "ignite-aws"},
-    "GoogleStorage": {"artifactId": "ignite-gce"},
-    "ZooKeeper": {"artifactId": "ignite-zookeeper"},
-
-    "Log4j": {"artifactId": "ignite-log4j"},
-    "Log4j2": {"artifactId": "ignite-log4j2"},
-    "JCL": {"artifactId": "ignite-jcl"},
-    "HadoopIgfsJcl": {"artifactId": "ignite-hadoop"},
-    "SLF4J": {"artifactId": "ignite-slf4j"},
-
-    "Generic": {"groupId": "com.mchange", "artifactId": "c3p0", "version": "0.9.5.1"},
-    "MySQL": {"groupId": "mysql", "artifactId": "mysql-connector-java", "version": "5.1.37"},
-    "PostgreSQL": {"groupId": "org.postgresql", "artifactId": "postgresql", "version": "9.4-1204-jdbc42"},
-    "H2": {"groupId": "com.h2database", "artifactId": "h2", "version": "1.3.175"},
-    "Oracle": {"groupId": "oracle", "artifactId": "jdbc", "version": "11.2", "jar": "ojdbc6.jar"},
-    "DB2": {"groupId": "ibm", "artifactId": "jdbc", "version": "4.19.26", "jar": "db2jcc4.jar"},
-    "SQLServer": {"groupId": "microsoft", "artifactId": "jdbc", "version": "4.1", "jar": "sqljdbc41.jar"}
-}

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/src/main/js/app/decorator/select.js
----------------------------------------------------------------------
diff --git a/modules/web-console/src/main/js/app/decorator/select.js b/modules/web-console/src/main/js/app/decorator/select.js
deleted file mode 100644
index 2d22707..0000000
--- a/modules/web-console/src/main/js/app/decorator/select.js
+++ /dev/null
@@ -1,77 +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 angular from 'angular';
-
-/**
- * Special decorator that fix problem in AngularStrap selectAll / deselectAll methods.
- * If this problem will be fixed in AngularStrap we can remove this delegate.
- */
-angular.module('mgcrea.ngStrap.select')
-    .decorator('$select', ['$delegate', ($delegate) => {
-        function SelectFactoryDecorated(element, controller, config) {
-            const delegate = $delegate(element, controller, config);
-
-            // Common vars.
-            const options = angular.extend({}, $delegate.defaults, config);
-
-            const scope = delegate.$scope;
-
-            const valueByIndex = (index) => {
-                if (angular.isUndefined(scope.$matches[index]))
-                    return null;
-
-                return scope.$matches[index].value;
-            };
-
-            const selectAll = (active) => {
-                const selected = [];
-
-                scope.$apply(() => {
-                    for (let i = 0; i < scope.$matches.length; i++) {
-                        if (scope.$isActive(i) === active) {
-                            selected[i] = scope.$matches[i].value;
-
-                            delegate.activate(i);
-
-                            controller.$setViewValue(scope.$activeIndex.map(valueByIndex));
-                        }
-                    }
-                });
-
-                // Emit events.
-                for (let i = 0; i < selected.length; i++) {
-                    if (selected[i])
-                        scope.$emit(options.prefixEvent + '.select', selected[i], i, delegate);
-                }
-            };
-
-            scope.$selectAll = () => {
-                scope.$$postDigest(selectAll.bind(this, false));
-            };
-
-            scope.$selectNone = () => {
-                scope.$$postDigest(selectAll.bind(this, true));
-            };
-
-            return delegate;
-        }
-
-        SelectFactoryDecorated.defaults = $delegate.defaults;
-
-        return SelectFactoryDecorated;
-    }]);

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/src/main/js/app/decorator/tooltip.js
----------------------------------------------------------------------
diff --git a/modules/web-console/src/main/js/app/decorator/tooltip.js b/modules/web-console/src/main/js/app/decorator/tooltip.js
deleted file mode 100644
index a47337a..0000000
--- a/modules/web-console/src/main/js/app/decorator/tooltip.js
+++ /dev/null
@@ -1,56 +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 angular from 'angular';
-
-/**
- * Special decorator that fix problem in AngularStrap $tooltip in special case.
- * Case: when tooltip is shown on table row remove button and user click this button.
- * If this problem will be fixed in AngularStrap we can remove this delegate.
- */
-angular.module('mgcrea.ngStrap.tooltip')
-    .decorator('$tooltip', ['$delegate', ($delegate) => {
-        function TooltipFactoryDecorated(element, config) {
-            const delegate = $delegate(element, config);
-
-            const scope = delegate.$scope;
-
-            const options = delegate.$options;
-
-            const hideWraped = delegate.hide;
-
-            delegate.hide = (blur) => {
-                if (!delegate.$isShown)
-                    return;
-
-                if (delegate.$element !== null)
-                    return hideWraped(blur);
-
-                scope.$emit(options.prefixEvent + '.hide.before', delegate);
-
-                if (angular.isDefined(options.onBeforeHide) && angular.isFunction(options.onBeforeHide))
-                    options.onBeforeHide(delegate);
-
-                delegate.$isShown = scope.$isShown = false;
-                scope.$$phase || (scope.$root && scope.$root.$$phase) || scope.$digest();
-            };
-
-            return delegate;
-        }
-
-        return TooltipFactoryDecorated;
-    }]);

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/src/main/js/app/directives/auto-focus.directive.js
----------------------------------------------------------------------
diff --git a/modules/web-console/src/main/js/app/directives/auto-focus.directive.js b/modules/web-console/src/main/js/app/directives/auto-focus.directive.js
deleted file mode 100644
index 326fe1f..0000000
--- a/modules/web-console/src/main/js/app/directives/auto-focus.directive.js
+++ /dev/null
@@ -1,26 +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.
- */
-
-// Directive to auto-focus specified element.
-export default ['igniteAutoFocus', ['$timeout', ($timeout) => {
-    return {
-        restrict: 'AC',
-        link(scope, element) {
-            $timeout(() => element[0].focus());
-        }
-    };
-}]];

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/src/main/js/app/directives/bs-affix-update.directive.js
----------------------------------------------------------------------
diff --git a/modules/web-console/src/main/js/app/directives/bs-affix-update.directive.js b/modules/web-console/src/main/js/app/directives/bs-affix-update.directive.js
deleted file mode 100644
index 925722c..0000000
--- a/modules/web-console/src/main/js/app/directives/bs-affix-update.directive.js
+++ /dev/null
@@ -1,34 +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 angular from 'angular';
-
-export default ['igniteBsAffixUpdate', ['$window', '$timeout', ($window, $timeout) => {
-    let update = null;
-
-    const link = ({$last}) => {
-        if ($last) {
-            update && $timeout.cancel(update);
-            update = $timeout(() => angular.element($window).triggerHandler('resize'), 1000);
-        }
-    };
-
-    return {
-        restrict: 'A',
-        link
-    };
-}]];

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/src/main/js/app/directives/centered/centered.css
----------------------------------------------------------------------
diff --git a/modules/web-console/src/main/js/app/directives/centered/centered.css b/modules/web-console/src/main/js/app/directives/centered/centered.css
deleted file mode 100644
index 694c1d2..0000000
--- a/modules/web-console/src/main/js/app/directives/centered/centered.css
+++ /dev/null
@@ -1,37 +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.
- */
-
-.center-container {
-    position: fixed;
-    top: 0;
-    left: 0;
-    height: 100%;
-    width: 100%;
-    display: table;
-    pointer-events: none;
-    z-index: 9999;
-}
-
-.centered {
-    display: table-cell;
-    vertical-align: middle;
-    text-align: center;
-}
-
-.centered > * {
-    pointer-events: auto;
-}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/src/main/js/app/directives/centered/centered.directive.js
----------------------------------------------------------------------
diff --git a/modules/web-console/src/main/js/app/directives/centered/centered.directive.js b/modules/web-console/src/main/js/app/directives/centered/centered.directive.js
deleted file mode 100644
index 4abd086..0000000
--- a/modules/web-console/src/main/js/app/directives/centered/centered.directive.js
+++ /dev/null
@@ -1,26 +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 './centered.css';
-
-export default ['centered', [() => {
-    return {
-        restrict: 'E',
-        transclude: true,
-        template: '<div class="center-container"><div class="centered"><div ng-transclude></div></div></div>'
-    };
-}]];

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/src/main/js/app/directives/copy-to-clipboard.directive.js
----------------------------------------------------------------------
diff --git a/modules/web-console/src/main/js/app/directives/copy-to-clipboard.directive.js b/modules/web-console/src/main/js/app/directives/copy-to-clipboard.directive.js
deleted file mode 100644
index ee2110e..0000000
--- a/modules/web-console/src/main/js/app/directives/copy-to-clipboard.directive.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.
- */
-
-// Directive for copy to clipboard.
-export default ['igniteCopyToClipboard', ['IgniteCopyToClipboard', (CopyToClipboard) => {
-    return {
-        restrict: 'A',
-        link(scope, element, attrs) {
-            element.bind('click', () => CopyToClipboard.copy(attrs.igniteCopyToClipboard));
-
-            if (!document.queryCommandSupported('copy'))
-                element.hide();
-        }
-    };
-}]];

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/src/main/js/app/directives/hide-on-state-change/hide-on-state-change.directive.js
----------------------------------------------------------------------
diff --git a/modules/web-console/src/main/js/app/directives/hide-on-state-change/hide-on-state-change.directive.js b/modules/web-console/src/main/js/app/directives/hide-on-state-change/hide-on-state-change.directive.js
deleted file mode 100644
index 98f1c57..0000000
--- a/modules/web-console/src/main/js/app/directives/hide-on-state-change/hide-on-state-change.directive.js
+++ /dev/null
@@ -1,31 +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 ['hideOnStateChange', ['$timeout', ($timeout) => {
-    const link = (scope, element) => {
-        scope.$on('$stateChangeSuccess', () => {
-            $timeout(() => {
-                element.fadeOut('slow');
-            });
-        });
-    };
-
-    return {
-        restrict: 'AE',
-        link
-    };
-}]];

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/src/main/js/app/directives/information/information.directive.js
----------------------------------------------------------------------
diff --git a/modules/web-console/src/main/js/app/directives/information/information.directive.js b/modules/web-console/src/main/js/app/directives/information/information.directive.js
deleted file mode 100644
index a9a2f8c..0000000
--- a/modules/web-console/src/main/js/app/directives/information/information.directive.js
+++ /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.
- */
-
-import templateUrl from './information.jade';
-
-export default ['igniteInformation', [() => {
-    return {
-        scope: {
-            title: '@'
-        },
-        restrict: 'E',
-        templateUrl,
-        replace: true,
-        transclude: true
-    };
-}]];

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/src/main/js/app/directives/information/information.jade
----------------------------------------------------------------------
diff --git a/modules/web-console/src/main/js/app/directives/information/information.jade b/modules/web-console/src/main/js/app/directives/information/information.jade
deleted file mode 100644
index b805d4a..0000000
--- a/modules/web-console/src/main/js/app/directives/information/information.jade
+++ /dev/null
@@ -1,20 +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.
-
-.block-information
-    span.icon.fa.fa-info-circle(ng-if='title')
-    h3(ng-if='title') {{::title}}
-    div(ng-transclude='')


[28/52] ignite git commit: Web Console beta-3.

Posted by ak...@apache.org.
http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/frontend/controllers/profile-controller.js
----------------------------------------------------------------------
diff --git a/modules/web-console/frontend/controllers/profile-controller.js b/modules/web-console/frontend/controllers/profile-controller.js
new file mode 100644
index 0000000..9499db5
--- /dev/null
+++ b/modules/web-console/frontend/controllers/profile-controller.js
@@ -0,0 +1,94 @@
+/*
+ * 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.
+ */
+
+// Controller for Profile screen.
+export default ['profileController', [
+    '$rootScope', '$scope', '$http', 'IgniteLegacyUtils', 'IgniteMessages', 'IgniteFocus', 'IgniteConfirm', 'IgniteCountries', 'User',
+    function($root, $scope, $http, LegacyUtils, Messages, Focus, Confirm, Countries, User) {
+        $scope.user = angular.copy($root.user);
+
+        $scope.countries = Countries.getAll();
+
+        $scope.generateToken = () => {
+            Confirm.confirm('Are you sure you want to change security token?')
+                .then(() => $scope.user.token = LegacyUtils.randomString(20));
+        };
+
+        const _passwordValid = () => {
+            const cur = $scope.user;
+
+            return !$scope.expandedPassword || (cur.password && cur.confirm && cur.password === cur.confirm);
+        };
+
+        const _profileChanged = () => {
+            const old = $root.user;
+            const cur = $scope.user;
+
+            return !_.isEqual(old, cur);
+        };
+
+        $scope.toggleToken = () => {
+            $scope.expandedToken = !$scope.expandedToken;
+
+            if (!$scope.expandedToken)
+                $scope.user.token = $root.user.token;
+        };
+
+        $scope.togglePassword = () => {
+            $scope.expandedPassword = !$scope.expandedPassword;
+
+            if ($scope.expandedPassword)
+                Focus.move('profile_password');
+            else {
+                delete $scope.user.password;
+                delete $scope.user.confirm;
+            }
+        };
+
+        $scope.profileCouldBeSaved = () => _profileChanged() && $scope.profileForm && $scope.profileForm.$valid && _passwordValid();
+
+        $scope.saveBtnTipText = () => {
+            if (!_profileChanged())
+                return 'Nothing to save';
+
+            if (!_passwordValid())
+                return 'Invalid password';
+
+            return $scope.profileForm && $scope.profileForm.$valid ? 'Save profile' : 'Invalid profile settings';
+        };
+
+        $scope.saveUser = () => {
+            $http.post('/api/v1/profile/save', $scope.user)
+                .catch(({data}) => Promise.reject(data))
+                .then(User.read)
+                .then(() => {
+                    if ($scope.expandedPassword)
+                        $scope.togglePassword();
+
+                    if ($scope.expandedToken)
+                        $scope.toggleToken();
+
+                    Messages.showInfo('Profile saved.');
+
+                    Focus.move('profile-username');
+
+                    $root.$broadcast('user', $scope.user);
+                })
+                .catch((err) => Messages.showError(Messages.errorMessage('Failed to save profile: ', err)));
+        };
+    }
+]];

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/frontend/generator/generator-common.js
----------------------------------------------------------------------
diff --git a/modules/web-console/frontend/generator/generator-common.js b/modules/web-console/frontend/generator/generator-common.js
new file mode 100644
index 0000000..124a1b7
--- /dev/null
+++ b/modules/web-console/frontend/generator/generator-common.js
@@ -0,0 +1,612 @@
+/*
+ * 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.
+ */
+
+// Entry point for common functions for code generation.
+const $generatorCommon = {};
+
+// Add leading zero.
+$generatorCommon.addLeadingZero = function(numberStr, minSize) {
+    if (typeof (numberStr) !== 'string')
+        numberStr = String(numberStr);
+
+    while (numberStr.length < minSize)
+        numberStr = '0' + numberStr;
+
+    return numberStr;
+};
+
+// Format date to string.
+$generatorCommon.formatDate = function(date) {
+    const dd = $generatorCommon.addLeadingZero(date.getDate(), 2);
+    const mm = $generatorCommon.addLeadingZero(date.getMonth() + 1, 2);
+
+    const yyyy = date.getFullYear();
+
+    return mm + '/' + dd + '/' + yyyy + ' ' + $generatorCommon.addLeadingZero(date.getHours(), 2) + ':' + $generatorCommon.addLeadingZero(date.getMinutes(), 2);
+};
+
+// Generate comment for generated XML, Java, ... files.
+$generatorCommon.mainComment = function mainComment() {
+    return 'This configuration was generated by Ignite Web Console (' + $generatorCommon.formatDate(new Date()) + ')';
+};
+
+// Create result holder with service functions and properties for XML and java code generation.
+$generatorCommon.builder = function(deep) {
+    if (_.isNil($generatorCommon.JavaTypes))
+        $generatorCommon.JavaTypes = angular.element(document.getElementById('app')).injector().get('JavaTypes');
+
+    const res = [];
+
+    res.deep = deep || 0;
+    res.needEmptyLine = false;
+    res.lineStart = true;
+    res.datasources = [];
+    res.imports = {};
+    res.staticImports = {};
+    res.vars = {};
+
+    res.safeDeep = 0;
+    res.safeNeedEmptyLine = false;
+    res.safeImports = {};
+    res.safeDatasources = [];
+    res.safePoint = -1;
+
+    res.mergeProps = function(fromRes) {
+        if ($generatorCommon.isDefinedAndNotEmpty(fromRes)) {
+            res.datasources = fromRes.datasources;
+
+            angular.extend(res.imports, fromRes.imports);
+            angular.extend(res.staticImports, fromRes.staticImports);
+            angular.extend(res.vars, fromRes.vars);
+        }
+    };
+
+    res.mergeLines = function(fromRes) {
+        if ($generatorCommon.isDefinedAndNotEmpty(fromRes)) {
+            if (res.needEmptyLine)
+                res.push('');
+
+            _.forEach(fromRes, function(line) {
+                res.append(line);
+            });
+        }
+    };
+
+    res.startSafeBlock = function() {
+        res.safeDeep = this.deep;
+        this.safeNeedEmptyLine = this.needEmptyLine;
+        this.safeImports = _.cloneDeep(this.imports);
+        this.safeStaticImports = _.cloneDeep(this.staticImports);
+        this.safeDatasources = this.datasources.slice();
+        this.safePoint = this.length;
+    };
+
+    res.rollbackSafeBlock = function() {
+        if (this.safePoint >= 0) {
+            this.splice(this.safePoint, this.length - this.safePoint);
+
+            this.deep = res.safeDeep;
+            this.needEmptyLine = this.safeNeedEmptyLine;
+            this.datasources = this.safeDatasources;
+            this.imports = this.safeImports;
+            this.staticImports = this.safeStaticImports;
+            this.safePoint = -1;
+        }
+    };
+
+    res.asString = function() {
+        return this.join('\n');
+    };
+
+    res.append = function(s) {
+        this.push((this.lineStart ? _.repeat('    ', this.deep) : '') + s);
+
+        return this;
+    };
+
+    res.line = function(s) {
+        if (s) {
+            if (res.needEmptyLine)
+                res.push('');
+
+            res.append(s);
+        }
+
+        res.needEmptyLine = false;
+
+        res.lineStart = true;
+
+        return res;
+    };
+
+    res.startBlock = function(s) {
+        if (s) {
+            if (this.needEmptyLine)
+                this.push('');
+
+            this.append(s);
+        }
+
+        this.needEmptyLine = false;
+
+        this.lineStart = true;
+
+        this.deep++;
+
+        return this;
+    };
+
+    res.endBlock = function(s) {
+        this.deep--;
+
+        if (s)
+            this.append(s);
+
+        this.lineStart = true;
+
+        return this;
+    };
+
+    res.softEmptyLine = function() {
+        this.needEmptyLine = this.length > 0;
+    };
+
+    res.emptyLineIfNeeded = function() {
+        if (this.needEmptyLine) {
+            this.push('');
+            this.lineStart = true;
+
+            this.needEmptyLine = false;
+        }
+    };
+
+    /**
+     * Add class to imports.
+     *
+     * @param clsName Full class name.
+     * @returns {String} Short class name or full class name in case of names conflict.
+     */
+    res.importClass = function(clsName) {
+        if ($generatorCommon.JavaTypes.isJavaPrimitive(clsName))
+            return clsName;
+
+        const fullClassName = $generatorCommon.JavaTypes.fullClassName(clsName);
+
+        const dotIdx = fullClassName.lastIndexOf('.');
+
+        const shortName = dotIdx > 0 ? fullClassName.substr(dotIdx + 1) : fullClassName;
+
+        if (this.imports[shortName]) {
+            if (this.imports[shortName] !== fullClassName)
+                return fullClassName; // Short class names conflict. Return full name.
+        }
+        else
+            this.imports[shortName] = fullClassName;
+
+        return shortName;
+    };
+
+    /**
+     * Add class to imports.
+     *
+     * @param member Static member.
+     * @returns {String} Short class name or full class name in case of names conflict.
+     */
+    res.importStatic = function(member) {
+        const dotIdx = member.lastIndexOf('.');
+
+        const shortName = dotIdx > 0 ? member.substr(dotIdx + 1) : member;
+
+        if (this.staticImports[shortName]) {
+            if (this.staticImports[shortName] !== member)
+                return member; // Short class names conflict. Return full name.
+        }
+        else
+            this.staticImports[shortName] = member;
+
+        return shortName;
+    };
+
+    /**
+     * @returns String with "java imports" section.
+     */
+    res.generateImports = function() {
+        const genImports = [];
+
+        for (const clsName in this.imports) {
+            if (this.imports.hasOwnProperty(clsName) && this.imports[clsName].lastIndexOf('java.lang.', 0) !== 0)
+                genImports.push('import ' + this.imports[clsName] + ';');
+        }
+
+        genImports.sort();
+
+        return genImports.join('\n');
+    };
+
+    /**
+     * @returns String with "java imports" section.
+     */
+    res.generateStaticImports = function() {
+        const statImports = [];
+
+        for (const clsName in this.staticImports) {
+            if (this.staticImports.hasOwnProperty(clsName) && this.staticImports[clsName].lastIndexOf('java.lang.', 0) !== 0)
+                statImports.push('import static ' + this.staticImports[clsName] + ';');
+        }
+
+        statImports.sort();
+
+        return statImports.join('\n');
+    };
+
+    return res;
+};
+
+// Eviction policies code generation descriptors.
+$generatorCommon.EVICTION_POLICIES = {
+    LRU: {
+        className: 'org.apache.ignite.cache.eviction.lru.LruEvictionPolicy',
+        fields: {batchSize: {dflt: 1}, maxMemorySize: null, maxSize: {dflt: 100000}}
+    },
+    FIFO: {
+        className: 'org.apache.ignite.cache.eviction.fifo.FifoEvictionPolicy',
+        fields: {batchSize: {dflt: 1}, maxMemorySize: null, maxSize: {dflt: 100000}}
+    },
+    SORTED: {
+        className: 'org.apache.ignite.cache.eviction.sorted.SortedEvictionPolicy',
+        fields: {batchSize: {dflt: 1}, maxMemorySize: null, maxSize: {dflt: 100000}}
+    }
+};
+
+// Marshaller code generation descriptors.
+$generatorCommon.MARSHALLERS = {
+    OptimizedMarshaller: {
+        className: 'org.apache.ignite.marshaller.optimized.OptimizedMarshaller',
+        fields: {poolSize: null, requireSerializable: null }
+    },
+    JdkMarshaller: {
+        className: 'org.apache.ignite.marshaller.jdk.JdkMarshaller',
+        fields: {}
+    }
+};
+
+// Pairs of supported databases and their JDBC dialects.
+$generatorCommon.JDBC_DIALECTS = {
+    Generic: 'org.apache.ignite.cache.store.jdbc.dialect.BasicJdbcDialect',
+    Oracle: 'org.apache.ignite.cache.store.jdbc.dialect.OracleDialect',
+    DB2: 'org.apache.ignite.cache.store.jdbc.dialect.DB2Dialect',
+    SQLServer: 'org.apache.ignite.cache.store.jdbc.dialect.SQLServerDialect',
+    MySQL: 'org.apache.ignite.cache.store.jdbc.dialect.MySQLDialect',
+    PostgreSQL: 'org.apache.ignite.cache.store.jdbc.dialect.BasicJdbcDialect',
+    H2: 'org.apache.ignite.cache.store.jdbc.dialect.H2Dialect'
+};
+
+// Return JDBC dialect full class name for specified database.
+$generatorCommon.jdbcDialectClassName = function(db) {
+    const dialectClsName = $generatorCommon.JDBC_DIALECTS[db];
+
+    return dialectClsName ? dialectClsName : 'Unknown database: ' + db;
+};
+
+// Generate default data cache for specified igfs instance.
+$generatorCommon.igfsDataCache = function(igfs) {
+    return {
+        name: igfs.name + '-data',
+        cacheMode: 'PARTITIONED',
+        atomicityMode: 'TRANSACTIONAL',
+        writeSynchronizationMode: 'FULL_SYNC',
+        backups: 0,
+        igfsAffinnityGroupSize: igfs.affinnityGroupSize || 512
+    };
+};
+
+// Generate default meta cache for specified igfs instance.
+$generatorCommon.igfsMetaCache = function(igfs) {
+    return {
+        name: igfs.name + '-meta',
+        cacheMode: 'REPLICATED',
+        atomicityMode: 'TRANSACTIONAL',
+        writeSynchronizationMode: 'FULL_SYNC'
+    };
+};
+
+// Pairs of supported databases and their data sources.
+$generatorCommon.DATA_SOURCES = {
+    Generic: 'com.mchange.v2.c3p0.ComboPooledDataSource',
+    Oracle: 'oracle.jdbc.pool.OracleDataSource',
+    DB2: 'com.ibm.db2.jcc.DB2DataSource',
+    SQLServer: 'com.microsoft.sqlserver.jdbc.SQLServerDataSource',
+    MySQL: 'com.mysql.jdbc.jdbc2.optional.MysqlDataSource',
+    PostgreSQL: 'org.postgresql.ds.PGPoolingDataSource',
+    H2: 'org.h2.jdbcx.JdbcDataSource'
+};
+
+// Return data source full class name for specified database.
+$generatorCommon.dataSourceClassName = function(db) {
+    const dsClsName = $generatorCommon.DATA_SOURCES[db];
+
+    return dsClsName ? dsClsName : 'Unknown database: ' + db;
+};
+
+// Store factories code generation descriptors.
+$generatorCommon.STORE_FACTORIES = {
+    CacheJdbcPojoStoreFactory: {
+        className: 'org.apache.ignite.cache.store.jdbc.CacheJdbcPojoStoreFactory',
+        suffix: 'JdbcPojo',
+        fields: {
+            configuration: {type: 'bean'}
+        }
+    },
+    CacheJdbcBlobStoreFactory: {
+        className: 'org.apache.ignite.cache.store.jdbc.CacheJdbcBlobStoreFactory',
+        suffix: 'JdbcBlob',
+        fields: {
+            initSchema: null,
+            createTableQuery: null,
+            loadQuery: null,
+            insertQuery: null,
+            updateQuery: null,
+            deleteQuery: null
+        }
+    },
+    CacheHibernateBlobStoreFactory: {
+        className: 'org.apache.ignite.cache.store.hibernate.CacheHibernateBlobStoreFactory',
+        suffix: 'Hibernate',
+        fields: {hibernateProperties: {type: 'propertiesAsList', propVarName: 'props'}}
+    }
+};
+
+// Swap space SPI code generation descriptor.
+$generatorCommon.SWAP_SPACE_SPI = {
+    className: 'org.apache.ignite.spi.swapspace.file.FileSwapSpaceSpi',
+    fields: {
+        baseDirectory: {type: 'path'},
+        readStripesNumber: null,
+        maximumSparsity: {type: 'float'},
+        maxWriteQueueSize: null,
+        writeBufferSize: null
+    }
+};
+
+// Transaction configuration code generation descriptor.
+$generatorCommon.TRANSACTION_CONFIGURATION = {
+    className: 'org.apache.ignite.configuration.TransactionConfiguration',
+    fields: {
+        defaultTxConcurrency: {type: 'enum', enumClass: 'org.apache.ignite.transactions.TransactionConcurrency', dflt: 'PESSIMISTIC'},
+        defaultTxIsolation: {type: 'enum', enumClass: 'org.apache.ignite.transactions.TransactionIsolation', dflt: 'REPEATABLE_READ'},
+        defaultTxTimeout: {dflt: 0},
+        pessimisticTxLogLinger: {dflt: 10000},
+        pessimisticTxLogSize: null,
+        txSerializableEnabled: null,
+        txManagerFactory: {type: 'bean'}
+    }
+};
+
+// SSL configuration code generation descriptor.
+$generatorCommon.SSL_CONFIGURATION_TRUST_FILE_FACTORY = {
+    className: 'org.apache.ignite.ssl.SslContextFactory',
+    fields: {
+        keyAlgorithm: null,
+        keyStoreFilePath: {type: 'path'},
+        keyStorePassword: {type: 'raw'},
+        keyStoreType: null,
+        protocol: null,
+        trustStoreFilePath: {type: 'path'},
+        trustStorePassword: {type: 'raw'},
+        trustStoreType: null
+    }
+};
+
+// SSL configuration code generation descriptor.
+$generatorCommon.SSL_CONFIGURATION_TRUST_MANAGER_FACTORY = {
+    className: 'org.apache.ignite.ssl.SslContextFactory',
+    fields: {
+        keyAlgorithm: null,
+        keyStoreFilePath: {type: 'path'},
+        keyStorePassword: {type: 'raw'},
+        keyStoreType: null,
+        protocol: null,
+        trustManagers: {type: 'array'}
+    }
+};
+
+// Communication configuration code generation descriptor.
+$generatorCommon.CONNECTOR_CONFIGURATION = {
+    className: 'org.apache.ignite.configuration.ConnectorConfiguration',
+    fields: {
+        jettyPath: null,
+        host: null,
+        port: {dflt: 11211},
+        portRange: {dflt: 100},
+        idleTimeout: {dflt: 7000},
+        idleQueryCursorTimeout: {dflt: 600000},
+        idleQueryCursorCheckFrequency: {dflt: 60000},
+        receiveBufferSize: {dflt: 32768},
+        sendBufferSize: {dflt: 32768},
+        sendQueueLimit: {dflt: 0},
+        directBuffer: {dflt: false},
+        noDelay: {dflt: true},
+        selectorCount: null,
+        threadPoolSize: null,
+        messageInterceptor: {type: 'bean'},
+        secretKey: null,
+        sslEnabled: {dflt: false}
+    }
+};
+
+// Communication configuration code generation descriptor.
+$generatorCommon.COMMUNICATION_CONFIGURATION = {
+    className: 'org.apache.ignite.spi.communication.tcp.TcpCommunicationSpi',
+    fields: {
+        listener: {type: 'bean'},
+        localAddress: null,
+        localPort: {dflt: 47100},
+        localPortRange: {dflt: 100},
+        sharedMemoryPort: {dflt: 48100},
+        directBuffer: {dflt: false},
+        directSendBuffer: {dflt: false},
+        idleConnectionTimeout: {dflt: 30000},
+        connectTimeout: {dflt: 5000},
+        maxConnectTimeout: {dflt: 600000},
+        reconnectCount: {dflt: 10},
+        socketSendBuffer: {dflt: 32768},
+        socketReceiveBuffer: {dflt: 32768},
+        messageQueueLimit: {dflt: 1024},
+        slowClientQueueLimit: null,
+        tcpNoDelay: {dflt: true},
+        ackSendThreshold: {dflt: 16},
+        unacknowledgedMessagesBufferSize: {dflt: 0},
+        socketWriteTimeout: {dflt: 2000},
+        selectorsCount: null,
+        addressResolver: {type: 'bean'}
+    }
+};
+
+// Communication configuration code generation descriptor.
+$generatorCommon.IGFS_IPC_CONFIGURATION = {
+    className: 'org.apache.ignite.igfs.IgfsIpcEndpointConfiguration',
+    fields: {
+        type: {type: 'enum', enumClass: 'org.apache.ignite.igfs.IgfsIpcEndpointType'},
+        host: {dflt: '127.0.0.1'},
+        port: {dflt: 10500},
+        memorySize: {dflt: 262144},
+        tokenDirectoryPath: {dflt: 'ipc/shmem'},
+        threadCount: null
+    }
+};
+
+// Check that cache has datasource.
+$generatorCommon.cacheHasDatasource = function(cache) {
+    if (cache.cacheStoreFactory && cache.cacheStoreFactory.kind) {
+        const storeFactory = cache.cacheStoreFactory[cache.cacheStoreFactory.kind];
+
+        return !!(storeFactory && (storeFactory.connectVia ? (storeFactory.connectVia === 'DataSource' ? storeFactory.dialect : false) : storeFactory.dialect)); // eslint-disable-line no-nested-ternary
+    }
+
+    return false;
+};
+
+$generatorCommon.secretPropertiesNeeded = function(cluster) {
+    return !_.isNil(_.find(cluster.caches, $generatorCommon.cacheHasDatasource)) || cluster.sslEnabled;
+};
+
+// Check that binary is configured.
+$generatorCommon.binaryIsDefined = function(binary) {
+    return binary && ($generatorCommon.isDefinedAndNotEmpty(binary.idMapper) || $generatorCommon.isDefinedAndNotEmpty(binary.nameMapper) ||
+        $generatorCommon.isDefinedAndNotEmpty(binary.serializer) || $generatorCommon.isDefinedAndNotEmpty(binary.typeConfigurations) ||
+        (!_.isNil(binary.compactFooter) && !binary.compactFooter));
+};
+
+// Extract domain model metadata location.
+$generatorCommon.domainQueryMetadata = function(domain) {
+    return domain.queryMetadata ? domain.queryMetadata : 'Configuration';
+};
+
+/**
+ * @param {Object} obj Object to check.
+ * @param {Array<String>} props Array of properties names.
+ * @returns {boolean} 'true' if
+ */
+$generatorCommon.hasAtLeastOneProperty = function(obj, props) {
+    return obj && props && _.findIndex(props, (prop) => !_.isNil(obj[prop])) >= 0;
+};
+
+/**
+ * Convert some name to valid java name.
+ *
+ * @param prefix To append to java name.
+ * @param name to convert.
+ * @returns {string} Valid java name.
+ */
+$generatorCommon.toJavaName = function(prefix, name) {
+    const javaName = name ? name.replace(/[^A-Za-z_0-9]+/g, '_') : 'dflt';
+
+    return prefix + javaName.charAt(0).toLocaleUpperCase() + javaName.slice(1);
+};
+
+/**
+ * @param v Value to check.
+ * @returns {boolean} 'true' if value defined and not empty string.
+ */
+$generatorCommon.isDefinedAndNotEmpty = function(v) {
+    let defined = !_.isNil(v);
+
+    if (defined && (_.isString(v) || _.isArray(v)))
+        defined = v.length > 0;
+
+    return defined;
+};
+
+/**
+ * @param {Object} obj Object to check.
+ * @param {Array<String>} props Properties names.
+ * @returns {boolean} 'true' if object contains at least one from specified properties.
+ */
+$generatorCommon.hasProperty = function(obj, props) {
+    for (const propName in props) {
+        if (props.hasOwnProperty(propName)) {
+            if (obj[propName])
+                return true;
+        }
+    }
+
+    return false;
+};
+
+/**
+ * Get class for selected implementation of Failover SPI.
+ *
+ * @param spi Failover SPI configuration.
+ * @returns {*} Class for selected implementation of Failover SPI.
+ */
+$generatorCommon.failoverSpiClass = function(spi) {
+    switch (spi.kind) {
+        case 'JobStealing': return 'org.apache.ignite.spi.failover.jobstealing.JobStealingFailoverSpi';
+        case 'Never': return 'org.apache.ignite.spi.failover.never.NeverFailoverSpi';
+        case 'Always': return 'org.apache.ignite.spi.failover.always.AlwaysFailoverSpi';
+        case 'Custom': return _.get(spi, 'Custom.class');
+        default: return 'Unknown';
+    }
+};
+
+$generatorCommon.loggerConfigured = function(logger) {
+    if (logger && logger.kind) {
+        const log = logger[logger.kind];
+
+        switch (logger.kind) {
+            case 'Log4j2': return log && $generatorCommon.isDefinedAndNotEmpty(log.path);
+
+            case 'Log4j':
+                if (!log || !log.mode)
+                    return false;
+
+                if (log.mode === 'Path')
+                    return $generatorCommon.isDefinedAndNotEmpty(log.path);
+
+                return true;
+
+            case 'Custom': return log && $generatorCommon.isDefinedAndNotEmpty(log.class);
+
+            default:
+                return true;
+        }
+    }
+
+    return false;
+};
+
+export default $generatorCommon;


[32/52] ignite git commit: Web Console beta-3.

Posted by ak...@apache.org.
http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/frontend/app/modules/states/configuration/igfs/misc.jade
----------------------------------------------------------------------
diff --git a/modules/web-console/frontend/app/modules/states/configuration/igfs/misc.jade b/modules/web-console/frontend/app/modules/states/configuration/igfs/misc.jade
new file mode 100644
index 0000000..cb4687a
--- /dev/null
+++ b/modules/web-console/frontend/app/modules/states/configuration/igfs/misc.jade
@@ -0,0 +1,108 @@
+//-
+    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.jade
+
+-var form = 'misc'
+-var model = 'backupItem'
+-var pathModesForm = 'miscPathModes'
+-var pathModes = model + '.pathModes'
+
+//- LEGACY mixin for LEGACY IGFS path modes table.
+mixin table-igfs-path-mode-edit(prefix, focusId, index)
+    -var keyModel = 'tblPathModes.' + prefix + 'Key'
+    -var valModel = 'tblPathModes.' + prefix + 'Value'
+
+    -var keyFocusId = prefix + 'Key' + focusId
+    -var valFocusId = prefix + 'Value' + focusId
+
+    .col-xs-8.col-sm-8.col-md-8
+        .fieldSep /
+        .input-tip
+            input.form-control(id=keyFocusId ignite-on-enter-focus-move=valFocusId type='text' ng-model=keyModel placeholder='Path' ignite-on-escape='tableReset()')
+    .col-xs-4.col-sm-4.col-md-4
+        -var arg = keyModel + ', ' + valModel
+        -var btnVisible = 'tablePairSaveVisible(tblPathModes, ' + index + ')'
+        -var btnSave = 'tablePairSave(tablePairValid, backupItem, tblPathModes, ' + index + ')'
+        -var btnVisibleAndSave = btnVisible + ' && ' + btnSave
+        +btn-save(btnVisible, btnSave)
+        .input-tip
+            button.select-toggle.form-control(id=valFocusId bs-select ng-model=valModel data-placeholder='Mode' bs-options='item.value as item.label for item in igfsModes' tabindex='0' ignite-on-enter=btnVisibleAndSave ignite-on-escape='tableReset()')
+
+.panel.panel-default(ng-form=form novalidate)
+    .panel-heading(bs-collapse-toggle='' ng-click='ui.loadPanel("#{form}")')
+        ignite-form-panel-chevron
+        label Miscellaneous
+        ignite-form-field-tooltip.tipLabel
+            | Various miscellaneous IGFS settings
+        ignite-form-revert
+    .panel-collapse(role='tabpanel' bs-collapse-target id=form)
+        .panel-body(ng-if='ui.isPanelLoaded("#{form}")')
+            .col-sm-6
+                .settings-row
+                    +number('Block size:', model + '.blockSize', '"blockSize"', 'true', '65536', '0', 'File data block size in bytes')
+                .settings-row
+                    +number('Stream buffer size:', model + '.streamBufferSize', '"streamBufferSize"', 'true', '65536', '0', 'Read/write buffer size for IGFS stream operations in bytes')
+                .settings-row
+                    +number('Maximum space size:', model + '.maxSpaceSize', '"maxSpaceSize"', 'true', '0', '0', 'Maximum space available for data cache to store file system entries')
+                .settings-row
+                    +number('Maximum task range length:', model + '.maximumTaskRangeLength', '"maximumTaskRangeLength"', 'true', '0', '0', 'Maximum default range size of a file being split during IGFS task execution')
+                .settings-row
+                    +number-min-max('Management port:', model + '.managementPort', '"managementPort"', 'true', '11400', '0', '65535', 'Port number for management endpoint')
+                .settings-row
+                    +number('Per node batch size:', model + '.perNodeBatchSize', '"perNodeBatchSize"', 'true', '100', '0', 'Number of file blocks collected on local node before sending batch to remote node')
+                .settings-row
+                    +number('Per node parallel batch count:', model + '.perNodeParallelBatchCount', '"perNodeParallelBatchCount"', 'true', '8', '0', 'Number of file block batches that can be concurrently sent to remote node')
+                .settings-row
+                    +number('Prefetch blocks:', model + '.prefetchBlocks', '"prefetchBlocks"', 'true', '0', '0', 'Number of pre-fetched blocks if specific file chunk is requested')
+                .settings-row
+                    +number('Sequential reads before prefetch:', model + '.sequentialReadsBeforePrefetch', '"sequentialReadsBeforePrefetch"', 'true', '0', '0', 'Amount of sequential block reads before prefetch is triggered')
+                .settings-row
+                    +number('Trash purge timeout:', model + '.trashPurgeTimeout', '"trashPurgeTimeout"', 'true', '1000', '0', 'Maximum timeout awaiting for trash purging in case data cache oversize is detected')
+                .settings-row
+                    +checkbox('Colocate metadata', model + '.colocateMetadata', '"colocateMetadata"', 'Whether to co-locate metadata on a single node')
+                .settings-row
+                    +checkbox('Relaxed consistency', model + '.relaxedConsistency', '"relaxedConsistency"',
+                        'If value of this flag is <b>true</b>, IGFS will skip expensive consistency checks<br/>\
+                        It is recommended to set this flag to <b>false</b> if your application has conflicting\
+                        operations, or you do not know how exactly users will use your system')
+                .settings-row
+                    +ignite-form-group(ng-model=pathModes ng-form=pathModesForm)
+                        ignite-form-field-label
+                            | Path modes
+                        ignite-form-group-tooltip
+                            | Map of path prefixes to IGFS modes used for them
+                        ignite-form-group-add(ng-click='tableNewItem(tblPathModes)')
+                            | Add path mode
+
+                        .group-content-empty(ng-if='!((#{pathModes} && #{pathModes}.length > 0) || tableNewItemActive(tblPathModes))') Not defined
+
+                        .group-content(ng-show='(#{pathModes} && #{pathModes}.length > 0) || tableNewItemActive(tblPathModes)')
+                            table.links-edit(id='pathModes' st-table=pathModes)
+                                tbody
+                                    tr(ng-repeat='item in #{pathModes}')
+                                        td.col-sm-12(ng-show='!tableEditing(tblPathModes, $index)')
+                                            a.labelFormField(ng-click='tableStartEdit(backupItem, tblPathModes, $index)') {{item.path + " [" + item.mode + "]"}}
+                                            +btn-remove('tableRemove(backupItem, tblPathModes, $index)', '"Remove path"')
+                                        td.col-sm-12(ng-show='tableEditing(tblPathModes, $index)')
+                                            +table-igfs-path-mode-edit('cur', '{{::tblPathModes.focusId + $index}}', '$index')
+                                tfoot(ng-show='tableNewItemActive(tblPathModes)')
+                                    tr
+                                        td.col-sm-12
+                                            +table-igfs-path-mode-edit('new', 'PathMode', '-1')
+
+            .col-sm-6
+                +preview-xml-java(model, 'igfsMisc')

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/frontend/app/modules/states/configuration/igfs/secondary.jade
----------------------------------------------------------------------
diff --git a/modules/web-console/frontend/app/modules/states/configuration/igfs/secondary.jade b/modules/web-console/frontend/app/modules/states/configuration/igfs/secondary.jade
new file mode 100644
index 0000000..0649527
--- /dev/null
+++ b/modules/web-console/frontend/app/modules/states/configuration/igfs/secondary.jade
@@ -0,0 +1,44 @@
+//-
+    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.jade
+
+-var form = 'secondaryFileSystem'
+-var model = 'backupItem'
+
+.panel.panel-default(ng-form=form novalidate)
+    .panel-heading(bs-collapse-toggle='' ng-click='ui.loadPanel("#{form}")')
+        ignite-form-panel-chevron
+        label(id="secondaryFileSystem-title") Secondary file system
+        ignite-form-field-tooltip.tipLabel
+            | Secondary file system is provided for pass-through, write-through, and read-through purposes
+        ignite-form-revert
+    .panel-collapse(role='tabpanel' bs-collapse-target id=form)
+        .panel-body(ng-if='ui.isPanelLoaded("#{form}")')
+            .col-sm-6
+                -var enabled = model + '.secondaryFileSystemEnabled'
+                -var secondaryFileSystem = model + '.secondaryFileSystem'
+
+                .settings-row
+                    +checkbox('Enabled', enabled, '"secondaryFileSystemEnabled"', 'Secondary file system enabled flag')
+                .settings-row
+                    +text-enabled('URI:', secondaryFileSystem + '.uri', '"hadoopURI"', enabled, 'false', 'hdfs://[namenodehost]:[port]/[path]', 'URI of file system')
+                .settings-row
+                    +text-enabled('Config path:', secondaryFileSystem + '.cfgPath', '"cfgPath"', enabled, 'false', 'Path to additional config', 'Additional path to Hadoop configuration')
+                .settings-row
+                    +text-enabled('User name:', secondaryFileSystem + '.userName', '"userName"', enabled, 'false', 'Input user name', 'User name')
+            .col-sm-6
+                +preview-xml-java(model, 'igfsSecondFS')

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/frontend/app/modules/states/configuration/preview-panel.directive.js
----------------------------------------------------------------------
diff --git a/modules/web-console/frontend/app/modules/states/configuration/preview-panel.directive.js b/modules/web-console/frontend/app/modules/states/configuration/preview-panel.directive.js
new file mode 100644
index 0000000..be7bf1e
--- /dev/null
+++ b/modules/web-console/frontend/app/modules/states/configuration/preview-panel.directive.js
@@ -0,0 +1,239 @@
+/*
+ * 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 ace from 'brace';
+
+export default ['previewPanel', ['$interval', '$timeout', ($interval, $timeout) => {
+    let animation = {editor: null, stage: 0, start: 0, stop: 0};
+    let prevContent = [];
+
+    const Range = ace.acequire('ace/range').Range;
+
+    const _clearSelection = (editor) => {
+        _.forEach(editor.session.getMarkers(false), (marker) => {
+            editor.session.removeMarker(marker.id);
+        });
+    };
+
+    /**
+     * Switch to next stage of animation.
+     */
+    const _animate = () => {
+        animation.stage += animation.step;
+
+        const stage = animation.stage;
+        const editor = animation.editor;
+
+        _clearSelection(editor);
+
+        animation.selections.forEach((selection) => {
+            editor.session.addMarker(new Range(selection.start, 0, selection.stop, 0),
+                'preview-highlight-' + stage, 'line', false);
+        });
+
+        if (stage === animation.finalStage) {
+            editor.animatePromise = null;
+
+            if (animation.clearOnFinal)
+                _clearSelection(editor);
+        }
+    };
+
+    /**
+     * Selection with animation.
+     *
+     * @param editor Editor to show selection animation.
+     * @param selections Array of selection intervals.
+     * @param step Step of animation (1 or -1).
+     * @param stage Start stage of animation.
+     * @param finalStage Final stage of animation.
+     * @param clearOnFinal Boolean flat to clear selection on animation finish.
+     */
+    const _fade = (editor, selections, step, stage, finalStage, clearOnFinal) => {
+        const promise = editor.animatePromise;
+
+        if (promise) {
+            $interval.cancel(promise);
+
+            _clearSelection(editor);
+        }
+
+        animation = {editor, selections, step, stage, finalStage, clearOnFinal};
+
+        editor.animatePromise = $interval(_animate, 100, 10, false);
+    };
+
+    /**
+     * Show selections with animation.
+     *
+     * @param editor Editor to show selection.
+     * @param selections Array of selection intervals.
+     */
+    const _fadeIn = (editor, selections) => {
+        _fade(editor, selections, 1, 0, 10, false);
+    };
+
+    /**
+     * Hide selections with animation.
+     *
+     * @param editor Editor to show selection.
+     * @param selections Array of selection intervals.
+     */
+    const _fadeOut = (editor, selections) => {
+        _fade(editor, selections, -1, 10, 0, true);
+    };
+
+    const onChange = ([content, editor]) => {
+        const {clearPromise} = editor;
+        const {lines} = content;
+
+        if (content.action === 'remove')
+            prevContent = lines;
+        else if (prevContent.length > 0 && lines.length > 0 && editor.attractAttention) {
+            if (clearPromise) {
+                $timeout.cancel(clearPromise);
+
+                _clearSelection(editor);
+            }
+
+            const selections = [];
+
+            let newIx = 0;
+            let prevIx = 0;
+
+            let prevLen = prevContent.length - (prevContent[prevContent.length - 1] === '' ? 1 : 0);
+            let newLen = lines.length - (lines[lines.length - 1] === '' ? 1 : 0);
+
+            const removed = newLen < prevLen;
+
+            let skipEnd = 0;
+
+            let selected = false;
+            let scrollTo = -1;
+
+            while (lines[newLen - 1] === prevContent[prevLen - 1] && newLen > 0 && prevLen > 0) {
+                prevLen -= 1;
+                newLen -= 1;
+
+                skipEnd += 1;
+            }
+
+            while (newIx < newLen || prevIx < prevLen) {
+                let start = -1;
+                let stop = -1;
+
+                // Find an index of a first line with different text.
+                for (; (newIx < newLen || prevIx < prevLen) && start < 0; newIx++, prevIx++) {
+                    if (newIx >= newLen || prevIx >= prevLen || lines[newIx] !== prevContent[prevIx]) {
+                        start = newIx;
+
+                        break;
+                    }
+                }
+
+                if (start >= 0) {
+                    // Find an index of a last line with different text by checking last string of old and new content in reverse order.
+                    for (let i = start; i < newLen && stop < 0; i++) {
+                        for (let j = prevIx; j < prevLen && stop < 0; j++) {
+                            if (lines[i] === prevContent[j] && lines[i] !== '') {
+                                stop = i;
+
+                                newIx = i;
+                                prevIx = j;
+
+                                break;
+                            }
+                        }
+                    }
+
+                    if (stop < 0) {
+                        stop = newLen;
+
+                        newIx = newLen;
+                        prevIx = prevLen;
+                    }
+
+                    if (start === stop) {
+                        if (removed)
+                            start = Math.max(0, start - 1);
+
+                        stop = Math.min(newLen + skipEnd, stop + 1);
+                    }
+
+                    if (start <= stop) {
+                        selections.push({start, stop});
+
+                        if (!selected)
+                            scrollTo = start;
+
+                        selected = true;
+                    }
+                }
+            }
+
+            // Run clear selection one time.
+            if (selected) {
+                _fadeIn(editor, selections);
+
+                editor.clearPromise = $timeout(() => {
+                    _fadeOut(editor, selections);
+
+                    editor.clearPromise = null;
+                }, 2000);
+
+                editor.scrollToRow(scrollTo);
+            }
+
+            prevContent = [];
+        }
+        else
+            editor.attractAttention = true;
+    };
+
+
+    const link = (scope, $element, $attrs, [igniteUiAceTabs1, igniteUiAceTabs2]) => {
+        const igniteUiAceTabs = igniteUiAceTabs1 || igniteUiAceTabs2;
+
+        if (!igniteUiAceTabs)
+            return;
+
+        igniteUiAceTabs.onLoad = (editor) => {
+            editor.setReadOnly(true);
+            editor.setOption('highlightActiveLine', false);
+            editor.setAutoScrollEditorIntoView(true);
+            editor.$blockScrolling = Infinity;
+            editor.attractAttention = false;
+
+            const renderer = editor.renderer;
+
+            renderer.setHighlightGutterLine(false);
+            renderer.setShowPrintMargin(false);
+            renderer.setOption('fontSize', '10px');
+            renderer.setOption('maxLines', '50');
+
+            editor.setTheme('ace/theme/chrome');
+        };
+
+        igniteUiAceTabs.onChange = onChange;
+    };
+
+    return {
+        restrict: 'C',
+        link,
+        require: ['?igniteUiAceTabs', '?^igniteUiAceTabs']
+    };
+}]];

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/frontend/app/modules/states/configuration/summary/summary-tabs.directive.js
----------------------------------------------------------------------
diff --git a/modules/web-console/frontend/app/modules/states/configuration/summary/summary-tabs.directive.js b/modules/web-console/frontend/app/modules/states/configuration/summary/summary-tabs.directive.js
new file mode 100644
index 0000000..f8094af
--- /dev/null
+++ b/modules/web-console/frontend/app/modules/states/configuration/summary/summary-tabs.directive.js
@@ -0,0 +1,50 @@
+/*
+ * 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 ['summaryTabs', [() => {
+    const link = (scope, $element, $attrs, [igniteUiAceTabs1, igniteUiAceTabs2]) => {
+        const igniteUiAceTabs = igniteUiAceTabs1 || igniteUiAceTabs2;
+
+        if (!igniteUiAceTabs)
+            return;
+
+        igniteUiAceTabs.onLoad = (editor) => {
+            editor.setReadOnly(true);
+            editor.setOption('highlightActiveLine', false);
+            editor.setAutoScrollEditorIntoView(true);
+            editor.$blockScrolling = Infinity;
+
+            const renderer = editor.renderer;
+
+            renderer.setHighlightGutterLine(false);
+            renderer.setShowPrintMargin(false);
+            renderer.setOption('fontFamily', 'monospace');
+            renderer.setOption('fontSize', '12px');
+            renderer.setOption('minLines', '25');
+            renderer.setOption('maxLines', '25');
+
+            editor.setTheme('ace/theme/chrome');
+        };
+    };
+
+    return {
+        priority: 1000,
+        restrict: 'C',
+        link,
+        require: ['?igniteUiAceTabs', '?^igniteUiAceTabs']
+    };
+}]];

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/frontend/app/modules/states/configuration/summary/summary.controller.js
----------------------------------------------------------------------
diff --git a/modules/web-console/frontend/app/modules/states/configuration/summary/summary.controller.js b/modules/web-console/frontend/app/modules/states/configuration/summary/summary.controller.js
new file mode 100644
index 0000000..f0cb842
--- /dev/null
+++ b/modules/web-console/frontend/app/modules/states/configuration/summary/summary.controller.js
@@ -0,0 +1,365 @@
+/*
+ * 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 _ from 'lodash';
+import JSZip from 'jszip';
+import saver from 'file-saver';
+
+export default [
+    '$rootScope', '$scope', '$http', 'IgniteLegacyUtils', 'IgniteMessages', 'IgniteLoading', '$filter', 'igniteConfigurationResource', 'JavaTypes', 'IgniteVersion', 'GeneratorDocker', 'GeneratorPom', 'IgniteFormUtils',
+    function($root, $scope, $http, LegacyUtils, Messages, Loading, $filter, Resource, JavaTypes, IgniteVersion, docker, pom, FormUtils) {
+        const ctrl = this;
+
+        $scope.ui = { ready: false };
+
+        Loading.start('summaryPage');
+
+        Resource.read()
+            .then(Resource.populate)
+            .then(({clusters}) => {
+                $scope.clusters = clusters;
+                $scope.clustersMap = {};
+                $scope.clustersView = _.map(clusters, (item) => {
+                    const {_id, name} = item;
+
+                    $scope.clustersMap[_id] = item;
+
+                    return {_id, name};
+                });
+
+                Loading.finish('summaryPage');
+
+                $scope.ui.ready = true;
+
+                if (!_.isEmpty(clusters)) {
+                    const idx = sessionStorage.summarySelectedId || 0;
+
+                    $scope.selectItem(clusters[idx]);
+                }
+            })
+            .catch(Messages.showError);
+
+        $scope.contentVisible = (rows, row) => {
+            return !row || !row._id || _.findIndex(rows, (item) => item._id === row._id) >= 0;
+        };
+
+        $scope.widthIsSufficient = FormUtils.widthIsSufficient;
+        $scope.dialects = {};
+
+        $scope.projectStructureOptions = {
+            nodeChildren: 'children',
+            dirSelectable: false,
+            injectClasses: {
+                iExpanded: 'fa fa-folder-open-o',
+                iCollapsed: 'fa fa-folder-o'
+            },
+            equality: (node1, node2) => {
+                return node1 === node2;
+            }
+        };
+
+        const javaConfigFolder = {
+            type: 'folder',
+            name: 'config',
+            children: [
+                { type: 'file', name: 'ClientConfigurationFactory.java' },
+                { type: 'file', name: 'ServerConfigurationFactory.java' }
+            ]
+        };
+
+        const javaStartupFolder = {
+            type: 'folder',
+            name: 'startup',
+            children: [
+                { type: 'file', name: 'ClientNodeCodeStartup.java' },
+                { type: 'file', name: 'ClientNodeSpringStartup.java' },
+                { type: 'file', name: 'ServerNodeCodeStartup.java' },
+                { type: 'file', name: 'ServerNodeSpringStartup.java' }
+            ]
+        };
+
+        const demoFolder = {
+            type: 'folder',
+            name: 'demo',
+            children: [
+                { type: 'file', name: 'DemoStartup.java' }
+            ]
+        };
+
+        const resourcesFolder = {
+            type: 'folder',
+            name: 'resources',
+            children: [
+                { type: 'file', name: 'secret.properties' }
+            ]
+        };
+
+        const javaFolder = {
+            type: 'folder',
+            name: 'java',
+            children: [
+                {
+                    type: 'folder',
+                    name: 'config',
+                    children: [
+                        javaConfigFolder,
+                        javaStartupFolder
+                    ]
+                }
+            ]
+        };
+
+        const clnCfg = { type: 'file', name: 'client.xml' };
+
+        const srvCfg = { type: 'file', name: 'server.xml' };
+
+        const mainFolder = {
+            type: 'folder',
+            name: 'main',
+            children: [javaFolder]
+        };
+
+        const projectStructureRoot = {
+            type: 'folder',
+            name: 'project.zip',
+            children: [
+                {
+                    type: 'folder',
+                    name: 'config',
+                    children: [clnCfg, srvCfg]
+                },
+                {
+                    type: 'folder',
+                    name: 'jdbc-drivers',
+                    children: [
+                        { type: 'file', name: 'README.txt' }
+                    ]
+                },
+                {
+                    type: 'folder',
+                    name: 'src',
+                    children: [mainFolder]
+                },
+                { type: 'file', name: '.dockerignore' },
+                { type: 'file', name: 'Dockerfile' },
+                { type: 'file', name: 'pom.xml' },
+                { type: 'file', name: 'README.txt' }
+            ]
+        };
+
+        $scope.projectStructure = [projectStructureRoot];
+
+        $scope.projectStructureExpanded = [projectStructureRoot];
+
+        $scope.tabsServer = { activeTab: 0 };
+        $scope.tabsClient = { activeTab: 0 };
+
+        /**
+         *
+         * @param {Object} node - Tree node.
+         * @param {string[]} path - Path to find.
+         * @returns {Object} Tree node.
+         */
+        function getOrCreateFolder(node, path) {
+            if (_.isEmpty(path))
+                return node;
+
+            const leaf = path.shift();
+
+            let children = null;
+
+            if (!_.isEmpty(node.children)) {
+                children = _.find(node.children, {type: 'folder', name: leaf});
+
+                if (children)
+                    return getOrCreateFolder(children, path);
+            }
+
+            children = {type: 'folder', name: leaf, children: []};
+
+            node.children.push(children);
+
+            node.children = _.orderBy(node.children, ['type', 'name'], ['desc', 'asc']);
+
+            return getOrCreateFolder(children, path);
+        }
+
+        function addClass(fullClsName) {
+            const path = fullClsName.split('.');
+            const leaf = {type: 'file', name: path.pop() + '.java'};
+            const folder = getOrCreateFolder(javaFolder, path);
+
+            if (!_.find(folder.children, leaf))
+                folder.children.push(leaf);
+        }
+
+        $scope.selectItem = (cluster) => {
+            delete ctrl.cluster;
+
+            if (!cluster)
+                return;
+
+            cluster = $scope.clustersMap[cluster._id];
+
+            ctrl.cluster = cluster;
+
+            $scope.cluster = cluster;
+            $scope.selectedItem = cluster;
+            $scope.dialects = {};
+
+            sessionStorage.summarySelectedId = $scope.clusters.indexOf(cluster);
+
+            mainFolder.children = [javaFolder];
+            javaFolder.children = [javaConfigFolder, javaStartupFolder];
+
+            if ($generatorCommon.secretPropertiesNeeded(cluster))
+                mainFolder.children.push(resourcesFolder);
+
+            if ($generatorJava.isDemoConfigured(cluster, $root.IgniteDemoMode))
+                javaFolder.children.push(demoFolder);
+
+            if (cluster.discovery.kind === 'Jdbc' && cluster.discovery.Jdbc.dialect)
+                $scope.dialects[cluster.discovery.Jdbc.dialect] = true;
+
+            _.forEach(cluster.caches, (cache) => {
+                if (cache.cacheStoreFactory) {
+                    const store = cache.cacheStoreFactory[cache.cacheStoreFactory.kind];
+
+                    if (store && store.dialect)
+                        $scope.dialects[store.dialect] = true;
+                }
+
+                _.forEach(cache.domains, (domain) => {
+                    if (!_.isEmpty(domain.keyFields)) {
+                        if (JavaTypes.nonBuiltInClass(domain.keyType))
+                            addClass(domain.keyType);
+
+                        addClass(domain.valueType);
+                    }
+                });
+            });
+
+            projectStructureRoot.name = cluster.name + '-project.zip';
+            clnCfg.name = cluster.name + '-client.xml';
+            srvCfg.name = cluster.name + '-server.xml';
+        };
+
+        $scope.$watch('cluster', (cluster) => {
+            if (!cluster)
+                return;
+
+            if (!$filter('hasPojo')(cluster) && $scope.tabsClient.activeTab === 3)
+                $scope.tabsClient.activeTab = 0;
+        });
+
+        $scope.$watch('cluster._id', () => {
+            $scope.tabsClient.init = [];
+            $scope.tabsServer.init = [];
+        });
+
+        // TODO IGNITE-2114: implemented as independent logic for download.
+        $scope.downloadConfiguration = function() {
+            const cluster = $scope.cluster;
+            const clientNearCfg = cluster.clientNearCfg;
+
+            const zip = new JSZip();
+
+            if (!ctrl.data)
+                ctrl.data = {};
+
+            if (!ctrl.data.docker)
+                ctrl.data.docker = docker.generate(cluster, 'latest');
+
+            zip.file('Dockerfile', ctrl.data.docker);
+            zip.file('.dockerignore', docker.ignoreFile());
+
+            const builder = $generatorProperties.generateProperties(cluster);
+
+            if (builder)
+                zip.file('src/main/resources/secret.properties', builder.asString());
+
+            const srcPath = 'src/main/java/';
+
+            const serverXml = 'config/' + cluster.name + '-server.xml';
+            const clientXml = 'config/' + cluster.name + '-client.xml';
+
+            zip.file(serverXml, $generatorXml.cluster(cluster));
+            zip.file(clientXml, $generatorXml.cluster(cluster, clientNearCfg));
+
+            zip.file(srcPath + 'config/ServerConfigurationFactory.java', $generatorJava.cluster(cluster, 'config', 'ServerConfigurationFactory', null));
+            zip.file(srcPath + 'config/ClientConfigurationFactory.java', $generatorJava.cluster(cluster, 'config', 'ClientConfigurationFactory', clientNearCfg));
+
+            if ($generatorJava.isDemoConfigured(cluster, $root.IgniteDemoMode)) {
+                zip.file(srcPath + 'demo/DemoStartup.java', $generatorJava.nodeStartup(cluster, 'demo', 'DemoStartup',
+                    'ServerConfigurationFactory.createConfiguration()', 'config.ServerConfigurationFactory'));
+            }
+
+            zip.file(srcPath + 'startup/ServerNodeSpringStartup.java', $generatorJava.nodeStartup(cluster, 'startup', 'ServerNodeSpringStartup', '"' + serverXml + '"'));
+            zip.file(srcPath + 'startup/ClientNodeSpringStartup.java', $generatorJava.nodeStartup(cluster, 'startup', 'ClientNodeSpringStartup', '"' + clientXml + '"'));
+
+            zip.file(srcPath + 'startup/ServerNodeCodeStartup.java', $generatorJava.nodeStartup(cluster, 'startup', 'ServerNodeCodeStartup',
+                'ServerConfigurationFactory.createConfiguration()', 'config.ServerConfigurationFactory'));
+            zip.file(srcPath + 'startup/ClientNodeCodeStartup.java', $generatorJava.nodeStartup(cluster, 'startup', 'ClientNodeCodeStartup',
+                'ClientConfigurationFactory.createConfiguration()', 'config.ClientConfigurationFactory', clientNearCfg));
+
+            zip.file('pom.xml', pom.generate(cluster, IgniteVersion.version).asString());
+
+            zip.file('README.txt', $generatorReadme.readme().asString());
+            zip.file('jdbc-drivers/README.txt', $generatorReadme.readmeJdbc().asString());
+
+            if (!ctrl.data.pojos)
+                ctrl.data.pojos = $generatorJava.pojos(cluster.caches);
+
+            for (const pojo of ctrl.data.pojos) {
+                if (pojo.keyClass && JavaTypes.nonBuiltInClass(pojo.keyType))
+                    zip.file(srcPath + pojo.keyType.replace(/\./g, '/') + '.java', pojo.keyClass);
+
+                zip.file(srcPath + pojo.valueType.replace(/\./g, '/') + '.java', pojo.valueClass);
+            }
+
+            $generatorOptional.optionalContent(zip, cluster);
+
+            zip.generateAsync({type: 'blob', compression: 'DEFLATE', mimeType: 'application/octet-stream'})
+                .then((blob) => saver.saveAs(blob, cluster.name + '-project.zip'));
+        };
+
+        /**
+         * @returns {boolean} 'true' if at least one proprietary JDBC driver is configured for cache store.
+         */
+        $scope.downloadJdbcDriversVisible = function() {
+            const dialects = $scope.dialects;
+
+            return !!(dialects.Oracle || dialects.DB2 || dialects.SQLServer);
+        };
+
+        /**
+         * Open download proprietary JDBC driver pages.
+         */
+        $scope.downloadJdbcDrivers = function() {
+            const dialects = $scope.dialects;
+
+            if (dialects.Oracle)
+                window.open('http://www.oracle.com/technetwork/apps-tech/jdbc-112010-090769.html');
+
+            if (dialects.DB2)
+                window.open('http://www-01.ibm.com/support/docview.wss?uid=swg21363866');
+
+            if (dialects.SQLServer)
+                window.open('https://www.microsoft.com/en-us/download/details.aspx?id=11774');
+        };
+    }
+];

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/frontend/app/modules/states/errors.state.js
----------------------------------------------------------------------
diff --git a/modules/web-console/frontend/app/modules/states/errors.state.js b/modules/web-console/frontend/app/modules/states/errors.state.js
new file mode 100644
index 0000000..2bdb80a
--- /dev/null
+++ b/modules/web-console/frontend/app/modules/states/errors.state.js
@@ -0,0 +1,43 @@
+/*
+ * 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 templateNotFoundPage from '../../../views/404.jade';
+import templateNotAuthorizedPage from '../../../views/403.jade';
+
+angular
+    .module('ignite-console.states.errors', [
+        'ui.router'
+    ])
+    .config(['$stateProvider', 'AclRouteProvider', function($stateProvider) {
+        // set up the states
+        $stateProvider
+            .state('404', {
+                url: '/404',
+                templateUrl: templateNotFoundPage,
+                metaTags: {
+                    title: 'Page not found'
+                }
+            })
+            .state('403', {
+                url: '/403',
+                templateUrl: templateNotAuthorizedPage,
+                metaTags: {
+                    title: 'Not authorized'
+                }
+            });
+    }]);

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/frontend/app/modules/states/logout.state.js
----------------------------------------------------------------------
diff --git a/modules/web-console/frontend/app/modules/states/logout.state.js b/modules/web-console/frontend/app/modules/states/logout.state.js
new file mode 100644
index 0000000..42795ea
--- /dev/null
+++ b/modules/web-console/frontend/app/modules/states/logout.state.js
@@ -0,0 +1,35 @@
+/*
+ * 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';
+
+angular
+.module('ignite-console.states.logout', [
+    'ui.router'
+])
+.config(['$stateProvider', 'AclRouteProvider', function($stateProvider, AclRoute) {
+    // set up the states
+    $stateProvider
+    .state('logout', {
+        url: '/logout',
+        onEnter: AclRoute.checkAccess('logout'),
+        controller: ['Auth', (Auth) => Auth.logout()],
+        metaTags: {
+            title: 'Logout'
+        }
+    });
+}]);

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/frontend/app/modules/states/password.state.js
----------------------------------------------------------------------
diff --git a/modules/web-console/frontend/app/modules/states/password.state.js b/modules/web-console/frontend/app/modules/states/password.state.js
new file mode 100644
index 0000000..48d01df
--- /dev/null
+++ b/modules/web-console/frontend/app/modules/states/password.state.js
@@ -0,0 +1,46 @@
+/*
+ * 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';
+
+angular
+.module('ignite-console.states.password', [
+    'ui.router'
+])
+.config(['$stateProvider', function($stateProvider) {
+    // set up the states
+    $stateProvider
+    .state('password', {
+        url: '/password',
+        abstract: true,
+        template: '<ui-view></ui-view>'
+    })
+    .state('password.reset', {
+        url: '/reset?{token}',
+        templateUrl: '/reset.html',
+        metaTags: {
+            title: 'Reset password'
+        }
+    })
+    .state('password.send', {
+        url: '/send',
+        templateUrl: '/reset.html',
+        metaTags: {
+            title: 'Password Send'
+        }
+    });
+}]);

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/frontend/app/modules/states/profile.state.js
----------------------------------------------------------------------
diff --git a/modules/web-console/frontend/app/modules/states/profile.state.js b/modules/web-console/frontend/app/modules/states/profile.state.js
new file mode 100644
index 0000000..9c31340
--- /dev/null
+++ b/modules/web-console/frontend/app/modules/states/profile.state.js
@@ -0,0 +1,35 @@
+/*
+ * 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';
+
+angular
+.module('ignite-console.states.profile', [
+    'ui.router'
+])
+.config(['$stateProvider', 'AclRouteProvider', function($stateProvider, AclRoute) {
+    // set up the states
+    $stateProvider
+    .state('settings.profile', {
+        url: '/profile',
+        templateUrl: '/settings/profile.html',
+        onEnter: AclRoute.checkAccess('profile'),
+        metaTags: {
+            title: 'User profile'
+        }
+    });
+}]);

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/frontend/app/modules/states/signin.state.js
----------------------------------------------------------------------
diff --git a/modules/web-console/frontend/app/modules/states/signin.state.js b/modules/web-console/frontend/app/modules/states/signin.state.js
new file mode 100644
index 0000000..14ebc1b
--- /dev/null
+++ b/modules/web-console/frontend/app/modules/states/signin.state.js
@@ -0,0 +1,43 @@
+/*
+ * 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 templateUrl from 'views/signin.jade';
+
+angular
+.module('ignite-console.states.login', [
+    'ui.router',
+    // services
+    'ignite-console.user'
+])
+.config(['$stateProvider', 'AclRouteProvider', function($stateProvider) {
+    // set up the states
+    $stateProvider
+    .state('signin', {
+        url: '/',
+        templateUrl,
+        resolve: {
+            user: ['$state', 'User', ($state, User) => {
+                return User.read()
+                    .then(() => $state.go('base.configuration.clusters'))
+                    .catch(() => {});
+            }]
+        },
+        metaTags: {
+        }
+    });
+}]);

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/frontend/app/modules/user/AclRoute.provider.js
----------------------------------------------------------------------
diff --git a/modules/web-console/frontend/app/modules/user/AclRoute.provider.js b/modules/web-console/frontend/app/modules/user/AclRoute.provider.js
new file mode 100644
index 0000000..40abea5
--- /dev/null
+++ b/modules/web-console/frontend/app/modules/user/AclRoute.provider.js
@@ -0,0 +1,47 @@
+/*
+ * 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 AclRoute {
+        static checkAccess = (permissions, failState) => {
+            failState = failState || '403';
+
+            return ['$state', 'AclService', 'User', ($state, AclService, User) => {
+                User.read()
+                    .then(() => {
+                        if (AclService.can(permissions))
+                            return;
+
+                        return $state.go(failState);
+                    })
+                    .catch(() => {
+                        User.clean();
+
+                        if ($state.current.name !== 'signin')
+                            $state.go('signin');
+                    });
+            }];
+        }
+    }
+
+    return {
+        checkAccess: AclRoute.checkAccess,
+        $get: () => {
+            return AclRoute;
+        }
+    };
+}];

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/frontend/app/modules/user/Auth.service.js
----------------------------------------------------------------------
diff --git a/modules/web-console/frontend/app/modules/user/Auth.service.js b/modules/web-console/frontend/app/modules/user/Auth.service.js
new file mode 100644
index 0000000..43e2f92
--- /dev/null
+++ b/modules/web-console/frontend/app/modules/user/Auth.service.js
@@ -0,0 +1,56 @@
+/*
+ * 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 ['Auth', ['$http', '$rootScope', '$state', '$window', 'IgniteErrorPopover', 'IgniteMessages', 'gettingStarted', 'User', 'IgniteAgentMonitor',
+    ($http, $root, $state, $window, ErrorPopover, Messages, gettingStarted, User, agentMonitor) => {
+        return {
+            forgotPassword(userInfo) {
+                $http.post('/api/v1/password/forgot', userInfo)
+                    .success(() => $state.go('password.send'))
+                    .error((err) => ErrorPopover.show('forgot_email', Messages.errorMessage(null, err)));
+            },
+            auth(action, userInfo) {
+                $http.post('/api/v1/' + action, userInfo)
+                    .catch(({data}) => Promise.reject(data))
+                    .then(() => {
+                        if (action === 'password/forgot')
+                            return;
+
+                        User.read()
+                            .then((user) => {
+                                $root.$broadcast('user', user);
+
+                                $state.go('base.configuration.clusters');
+
+                                agentMonitor.init();
+
+                                $root.gettingStarted.tryShow();
+                            });
+                    })
+                    .catch((err) => ErrorPopover.show(action + '_email', Messages.errorMessage(null, err)));
+            },
+            logout() {
+                $http.post('/api/v1/logout')
+                    .success(() => {
+                        User.clean();
+
+                        $window.open($state.href('signin'), '_self');
+                    })
+                    .error(Messages.showError);
+            }
+        };
+    }]];

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/frontend/app/modules/user/User.service.js
----------------------------------------------------------------------
diff --git a/modules/web-console/frontend/app/modules/user/User.service.js b/modules/web-console/frontend/app/modules/user/User.service.js
new file mode 100644
index 0000000..8b9a1e7
--- /dev/null
+++ b/modules/web-console/frontend/app/modules/user/User.service.js
@@ -0,0 +1,51 @@
+/*
+ * 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 ['User', ['$q', '$injector', '$rootScope', '$state', '$http', function($q, $injector, $root, $state, $http) {
+    let user;
+
+    return {
+        load() {
+            return user = $http.post('/api/v1/user')
+                .then(({data}) => {
+                    $root.user = data;
+
+                    $root.$broadcast('user', $root.user);
+
+                    return $root.user;
+                })
+                .catch(({data}) => {
+                    user = null;
+
+                    return $q.reject(data);
+                });
+        },
+        read() {
+            if (user)
+                return user;
+
+            return this.load();
+        },
+        clean() {
+            delete $root.user;
+
+            delete $root.IgniteDemoMode;
+
+            sessionStorage.removeItem('IgniteDemoMode');
+        }
+    };
+}]];

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/frontend/app/modules/user/permissions.js
----------------------------------------------------------------------
diff --git a/modules/web-console/frontend/app/modules/user/permissions.js b/modules/web-console/frontend/app/modules/user/permissions.js
new file mode 100644
index 0000000..e13509c
--- /dev/null
+++ b/modules/web-console/frontend/app/modules/user/permissions.js
@@ -0,0 +1,28 @@
+/*
+ * 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 guest = ['login'];
+const becomed = ['profile', 'configuration', 'query'];
+const user = becomed.concat(['logout']);
+const admin = user.concat(['admin_page']);
+
+export default {
+    guest,
+    user,
+    admin,
+    becomed
+};

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/frontend/app/modules/user/user.module.js
----------------------------------------------------------------------
diff --git a/modules/web-console/frontend/app/modules/user/user.module.js b/modules/web-console/frontend/app/modules/user/user.module.js
new file mode 100644
index 0000000..11798d0
--- /dev/null
+++ b/modules/web-console/frontend/app/modules/user/user.module.js
@@ -0,0 +1,73 @@
+/*
+ * 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 aclData from './permissions';
+
+import Auth from './Auth.service';
+import User from './User.service';
+import AclRouteProvider from './AclRoute.provider';
+
+angular
+.module('ignite-console.user', [
+    'mm.acl',
+    'ignite-console.config'
+])
+.factory('sessionRecoverer', ['$injector', '$q', ($injector, $q) => {
+    return {
+        responseError: (response) => {
+            // Session has expired
+            if (response.status === 401) {
+                $injector.get('User').clean();
+
+                const $state = $injector.get('$state');
+
+                if ($state.current.name !== 'signin')
+                    $state.go('signin');
+            }
+
+            return $q.reject(response);
+        }
+    };
+}])
+.config(['$httpProvider', ($httpProvider) => {
+    $httpProvider.interceptors.push('sessionRecoverer');
+}])
+.service(...Auth)
+.service(...User)
+.provider('AclRoute', AclRouteProvider)
+.run(['$rootScope', 'AclService', ($root, AclService) => {
+    AclService.setAbilities(aclData);
+    AclService.attachRole('guest');
+
+    $root.$on('user', (event, user) => {
+        if (!user)
+            return;
+
+        AclService.flushRoles();
+
+        let role = 'user';
+
+        if (user.admin)
+            role = 'admin';
+
+        if (user.becomeUsed)
+            role = 'becomed';
+
+        AclService.attachRole(role);
+    });
+}]);

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/frontend/app/modules/version/Version.provider.js
----------------------------------------------------------------------
diff --git a/modules/web-console/frontend/app/modules/version/Version.provider.js b/modules/web-console/frontend/app/modules/version/Version.provider.js
new file mode 100644
index 0000000..fe503ab
--- /dev/null
+++ b/modules/web-console/frontend/app/modules/version/Version.provider.js
@@ -0,0 +1,32 @@
+/*
+ * 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';
+
+angular
+    .module('ignite-console.version', [])
+    .provider('IgniteVersion', function() {
+        const version = {
+            version: '1.6.0'
+        };
+
+        this.update = (newVersion) => {
+            version.version = newVersion;
+        };
+
+        this.$get = [() => version];
+    });

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/frontend/app/services/ChartColors.service.js
----------------------------------------------------------------------
diff --git a/modules/web-console/frontend/app/services/ChartColors.service.js b/modules/web-console/frontend/app/services/ChartColors.service.js
new file mode 100644
index 0000000..843aa5c
--- /dev/null
+++ b/modules/web-console/frontend/app/services/ChartColors.service.js
@@ -0,0 +1,22 @@
+/*
+ * 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 COLORS from 'app/data/colors.json';
+
+export default ['IgniteChartColors', function() {
+    return COLORS;
+}];

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/frontend/app/services/Clone.service.js
----------------------------------------------------------------------
diff --git a/modules/web-console/frontend/app/services/Clone.service.js b/modules/web-console/frontend/app/services/Clone.service.js
new file mode 100644
index 0000000..52a4e4e
--- /dev/null
+++ b/modules/web-console/frontend/app/services/Clone.service.js
@@ -0,0 +1,64 @@
+/*
+ * 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.
+ */
+
+// Service for clone objects.
+export default ['IgniteClone', ['$rootScope', '$q', '$modal', ($root, $q, $modal) => {
+    const scope = $root.$new();
+
+    let _names = [];
+    let deferred;
+    let _validator;
+
+    function _nextAvailableName(name) {
+        let num = 1;
+        let tmpName = name;
+
+        while (_.includes(_names, tmpName)) {
+            tmpName = name + '_' + num.toString();
+
+            num++;
+        }
+
+        return tmpName;
+    }
+
+    const cloneModal = $modal({templateUrl: '/templates/clone.html', scope, placement: 'center', show: false});
+
+    scope.ok = function(newName) {
+        if (!_validator || _validator(newName)) {
+            deferred.resolve(_nextAvailableName(newName));
+
+            cloneModal.hide();
+        }
+    };
+
+    cloneModal.confirm = function(oldName, names, validator) {
+        _names = names;
+
+        scope.newName = _nextAvailableName(oldName);
+
+        _validator = validator;
+
+        deferred = $q.defer();
+
+        cloneModal.$promise.then(cloneModal.show);
+
+        return deferred.promise;
+    };
+
+    return cloneModal;
+}]];

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/frontend/app/services/Confirm.service.js
----------------------------------------------------------------------
diff --git a/modules/web-console/frontend/app/services/Confirm.service.js b/modules/web-console/frontend/app/services/Confirm.service.js
new file mode 100644
index 0000000..8208ea2
--- /dev/null
+++ b/modules/web-console/frontend/app/services/Confirm.service.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.
+ */
+
+// Confirm popup service.
+export default ['IgniteConfirm', ['$rootScope', '$q', '$modal', '$animate', ($root, $q, $modal, $animate) => {
+    const scope = $root.$new();
+
+    const modal = $modal({templateUrl: '/templates/confirm.html', scope, placement: 'center', show: false, backdrop: true});
+
+    const _hide = () => {
+        $animate.enabled(modal.$element, false);
+
+        modal.hide();
+    };
+
+    let deferred;
+
+    scope.confirmYes = () => {
+        _hide();
+
+        deferred.resolve(true);
+    };
+
+    scope.confirmNo = () => {
+        _hide();
+
+        deferred.resolve(false);
+    };
+
+    scope.confirmCancel = () => {
+        _hide();
+
+        deferred.reject('cancelled');
+    };
+
+    /**
+     *
+     * @param {String } content
+     * @param {Boolean} [yesNo]
+     * @returns {Promise}
+     */
+    modal.confirm = (content, yesNo) => {
+        scope.content = content || 'Confirm?';
+        scope.yesNo = !!yesNo;
+
+        deferred = $q.defer();
+
+        modal.$promise.then(modal.show);
+
+        return deferred.promise;
+    };
+
+    return modal;
+}]];

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/frontend/app/services/ConfirmBatch.service.js
----------------------------------------------------------------------
diff --git a/modules/web-console/frontend/app/services/ConfirmBatch.service.js b/modules/web-console/frontend/app/services/ConfirmBatch.service.js
new file mode 100644
index 0000000..ef66335
--- /dev/null
+++ b/modules/web-console/frontend/app/services/ConfirmBatch.service.js
@@ -0,0 +1,92 @@
+/*
+ * 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.
+ */
+
+// Service for confirm or skip several steps.
+export default ['IgniteConfirmBatch', ['$rootScope', '$q', '$modal', ($root, $q, $modal) => {
+    const scope = $root.$new();
+
+    scope.confirmModal = $modal({
+        templateUrl: '/templates/batch-confirm.html',
+        scope,
+        placement: 'center',
+        show: false,
+        backdrop: 'static',
+        keyboard: false
+    });
+
+    const _done = (cancel) => {
+        scope.confirmModal.hide();
+
+        if (cancel)
+            scope.deferred.reject('cancelled');
+        else
+            scope.deferred.resolve();
+    };
+
+    const _nextElement = (skip) => {
+        scope.items[scope.curIx++].skip = skip;
+
+        if (scope.curIx < scope.items.length)
+            scope.content = scope.contentGenerator(scope.items[scope.curIx]);
+        else
+            _done();
+    };
+
+    scope.cancel = () => {
+        _done(true);
+    };
+
+    scope.skip = (applyToAll) => {
+        if (applyToAll) {
+            for (let i = scope.curIx; i < scope.items.length; i++)
+                scope.items[i].skip = true;
+
+            _done();
+        }
+        else
+            _nextElement(true);
+    };
+
+    scope.overwrite = (applyToAll) => {
+        if (applyToAll)
+            _done();
+        else
+            _nextElement(false);
+    };
+
+    return {
+        /**
+         * Show confirm all dialog.
+         *
+         * @param confirmMessageFn Function to generate a confirm message.
+         * @param itemsToConfirm Array of element to process by confirm.
+         */
+        confirm(confirmMessageFn, itemsToConfirm) {
+            scope.deferred = $q.defer();
+
+            scope.contentGenerator = confirmMessageFn;
+
+            scope.items = itemsToConfirm;
+            scope.curIx = 0;
+            scope.content = (scope.items && scope.items.length > 0) ? scope.contentGenerator(scope.items[0]) : null;
+
+            scope.confirmModal.$promise.then(scope.confirmModal.show);
+
+            return scope.deferred.promise;
+        }
+    };
+}]];

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/frontend/app/services/CopyToClipboard.service.js
----------------------------------------------------------------------
diff --git a/modules/web-console/frontend/app/services/CopyToClipboard.service.js b/modules/web-console/frontend/app/services/CopyToClipboard.service.js
new file mode 100644
index 0000000..74c4764
--- /dev/null
+++ b/modules/web-console/frontend/app/services/CopyToClipboard.service.js
@@ -0,0 +1,50 @@
+/*
+ * 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.
+ */
+
+// Service to copy some value to OS clipboard.
+export default ['IgniteCopyToClipboard', ['$window', 'IgniteMessages', ($window, Messages) => {
+    const body = angular.element($window.document.body);
+
+    const textArea = angular.element('<textarea/>');
+
+    textArea.css({
+        position: 'fixed',
+        opacity: '0'
+    });
+
+    return {
+        copy(toCopy) {
+            textArea.val(toCopy);
+
+            body.append(textArea);
+
+            textArea[0].select();
+
+            try {
+                if (document.execCommand('copy'))
+                    Messages.showInfo('Value copied to clipboard');
+                else
+                    window.prompt('Copy to clipboard: Ctrl+C, Enter', toCopy);  // eslint-disable-line no-alert
+            }
+            catch (err) {
+                window.prompt('Copy to clipboard: Ctrl+C, Enter', toCopy);  // eslint-disable-line no-alert
+            }
+
+            textArea.remove();
+        }
+    };
+}]];

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/frontend/app/services/Countries.service.js
----------------------------------------------------------------------
diff --git a/modules/web-console/frontend/app/services/Countries.service.js b/modules/web-console/frontend/app/services/Countries.service.js
new file mode 100644
index 0000000..5ad3e6a
--- /dev/null
+++ b/modules/web-console/frontend/app/services/Countries.service.js
@@ -0,0 +1,31 @@
+/*
+ * 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 COUNTRIES from 'app/data/countries.json';
+
+export default ['IgniteCountries', function() {
+    const indexByName = _.keyBy(COUNTRIES, 'name');
+    const UNDEFINED_COUNTRY = {name: '', code: ''};
+
+    const getByName = (name) => (indexByName[name] || UNDEFINED_COUNTRY);
+    const getAll = () => (COUNTRIES);
+
+    return {
+        getByName,
+        getAll
+    };
+}];

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/frontend/app/services/ErrorPopover.service.js
----------------------------------------------------------------------
diff --git a/modules/web-console/frontend/app/services/ErrorPopover.service.js b/modules/web-console/frontend/app/services/ErrorPopover.service.js
new file mode 100644
index 0000000..85e4fda
--- /dev/null
+++ b/modules/web-console/frontend/app/services/ErrorPopover.service.js
@@ -0,0 +1,126 @@
+/*
+ * 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 ErrorPopover {
+    static $inject = ['$popover', '$anchorScroll', '$location', '$timeout', 'IgniteFormUtils'];
+
+    /**
+     * @param $popover
+     * @param $anchorScroll
+     * @param $location
+     * @param $timeout
+     * @param FormUtils
+     */
+    constructor($popover, $anchorScroll, $location, $timeout, FormUtils) {
+        this.$popover = $popover;
+        this.$anchorScroll = $anchorScroll;
+        this.$location = $location;
+        this.$timeout = $timeout;
+        this.FormUtils = FormUtils;
+
+        this.$anchorScroll.yOffset = 55;
+
+        this._popover = null;
+    }
+
+    /**
+     * Check that element is document area.
+     *
+     * @param el Element to check.
+     * @returns {boolean} True when element in document area.
+     */
+    static _isElementInViewport(el) {
+        const rect = el.getBoundingClientRect();
+
+        return (
+            rect.top >= 0 &&
+            rect.left >= 0 &&
+            rect.bottom <= (window.innerHeight || document.documentElement.clientHeight) &&
+            rect.right <= (window.innerWidth || document.documentElement.clientWidth)
+        );
+    }
+
+    /**
+     * Internal show popover message with detected properties.
+     *
+     * @param id Id element to show popover message.
+     * @param message Message to show.
+     * @param showTime Time before popover will be hidden.
+     */
+    _show(id, message, showTime = 5000) {
+        const body = $('body');
+
+        let el = body.find('#' + id);
+
+        if (!el || el.length === 0)
+            el = body.find('[name="' + id + '"]');
+
+        if (el && el.length > 0) {
+            if (!ErrorPopover._isElementInViewport(el[0])) {
+                this.$location.hash(el[0].id);
+
+                this.$anchorScroll();
+            }
+
+            const newPopover = this.$popover(el, {content: message});
+
+            this._popover = newPopover;
+
+            this.$timeout(() => newPopover.$promise.then(() => {
+                newPopover.show();
+
+                // Workaround to fix popover location when content is longer than content template.
+                // https://github.com/mgcrea/angular-strap/issues/1497
+                this.$timeout(newPopover.$applyPlacement);
+            }), 400);
+            this.$timeout(() => newPopover.hide(), showTime);
+        }
+    }
+
+    /**
+     * Show popover message.
+     *
+     * @param {String} id ID of element to show popover.
+     * @param {String} message Message to show.
+     * @param {Object} [ui] Form UI object. When specified extend section with that name.
+     * @param {String} [panelId] ID of element owner panel. When specified focus element with that ID.
+     * @param {Number} [showTime] Time before popover will be hidden. 5 sec when not specified.
+     * @returns {boolean} False always.
+     */
+    show(id, message, ui, panelId, showTime) {
+        if (this._popover)
+            this._popover.hide();
+
+        if (ui) {
+            this.FormUtils.ensureActivePanel(ui, panelId, id);
+
+            this.$timeout(() => this._show(id, message, showTime), ui.isPanelLoaded(panelId) ? 200 : 500);
+        }
+        else
+            this._show(id, message);
+
+        return false;
+    }
+
+    /**
+     * Hide popover message.
+     */
+    hide() {
+        if (this._popover)
+            this._popover.hide();
+    }
+}

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/frontend/app/services/Focus.service.js
----------------------------------------------------------------------
diff --git a/modules/web-console/frontend/app/services/Focus.service.js b/modules/web-console/frontend/app/services/Focus.service.js
new file mode 100644
index 0000000..a07e181
--- /dev/null
+++ b/modules/web-console/frontend/app/services/Focus.service.js
@@ -0,0 +1,33 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+// Service to transfer focus for specified element.
+export default ['IgniteFocus', ['$timeout', ($timeout) => {
+    return {
+        move(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(() => {
+                const elem = $('#' + id);
+
+                if (elem.length > 0)
+                    elem[0].focus();
+            }, 100);
+        }
+    };
+}]];


[06/52] ignite git commit: Web Console beta-3.

Posted by ak...@apache.org.
http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/src/main/js/public/stylesheets/style.scss
----------------------------------------------------------------------
diff --git a/modules/web-console/src/main/js/public/stylesheets/style.scss b/modules/web-console/src/main/js/public/stylesheets/style.scss
deleted file mode 100644
index 9f35637..0000000
--- a/modules/web-console/src/main/js/public/stylesheets/style.scss
+++ /dev/null
@@ -1,2156 +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 "./font-awesome-custom";
-@import "./bootstrap-custom";
-@import "./variables";
-
-@import "./../../app/directives/information/information.scss";
-
-@font-face {
-    font-family: 'Roboto Slab';
-    font-style: normal;
-    font-weight: 400;
-    src: local('Roboto Slab Regular'), local('RobotoSlab-Regular'), url(https://fonts.gstatic.com/s/robotoslab/v6/y7lebkjgREBJK96VQi37ZiwlidHJgAgmTjOEEzwu1L8.ttf) format('truetype');
-}
-
-@font-face {
-    font-family: 'Roboto Slab';
-    font-style: normal;
-    font-weight: 700;
-    src: local('Roboto Slab Bold'), local('RobotoSlab-Bold'), url(https://fonts.gstatic.com/s/robotoslab/v6/dazS1PrQQuCxC3iOAJFEJTdGNerWpg2Hn6A-BxWgZ_I.ttf) format('truetype');
-}
-
-hr {
-    margin: 20px 0;
-}
-
-.theme-line a.active {
-    font-weight: bold;
-    font-size: 1.1em;
-}
-
-.theme-line a:focus {
-    text-decoration: underline;
-    outline: none;
-}
-
-.navbar-default .navbar-brand, .navbar-default .navbar-brand:hover {
-    position: absolute;
-    left: 0;
-    text-align: center;
-}
-
-.navbar-brand {
-    padding: 5px 0;
-    margin: 10px 0;
-}
-
-.modal.center .modal-dialog {
-    position: fixed;
-    top: 50%;
-    left: 50%;
-    -webkit-transform: translateX(-50%) translateY(-50%);
-    transform: translateX(-50%) translateY(-50%);
-}
-
-.border-left {
-    box-shadow: 1px 0 0 0 $gray-lighter inset;
-}
-
-.border-right {
-    box-shadow: 1px 0 0 0 $gray-lighter;
-}
-
-.theme-line header {
-    background-color: $ignite-background-color;
-}
-
-.theme-line .docs-header h1 {
-    color: $ignite-header-color;
-    margin-top: 0;
-    font-size: 22px;
-}
-
-.theme-line .footer {
-    text-align: center;
-}
-
-.table.table-vertical-middle tbody > tr > td {
-  vertical-align: middle;
-}
-
-ul.navbar-nav, .sidebar-nav {
-    li.active > a {
-        color: $link-color;
-    }
-
-    li.active > a:not(.dropdown-toggle) {
-        cursor: default;
-        pointer-events: none;
-    }
-}
-
-.theme-line .sidebar-nav {
-    padding-bottom: 30px;
-
-    ul {
-        padding: 0;
-        list-style: none;
-        margin: 3px 0 0;
-
-        li {
-            line-height: $input-height;
-
-            a {
-                font-size: 18px;
-                color: $ignite-header-color;
-                position: relative;
-                white-space: nowrap;
-                overflow: hidden;
-                -o-text-overflow: ellipsis;
-                text-overflow: ellipsis;
-
-                span.fa-stack {
-                    margin-right: 5px;
-                    font-size: 12px;
-                    height: 26px;
-                }
-            }
-
-            a:hover { color: $link-hover-color; }
-
-            a.active {
-                color: $link-color;
-            }
-        }
-    }
-}
-
-.theme-line .sidebar-nav ul li a:hover {
-    text-decoration: none;
-}
-
-.theme-line .select {
-    li a.active {
-        color: $dropdown-link-active-color;
-    }
-
-    li a:hover {
-        color: $dropdown-link-hover-color;
-    }
-}
-
-.theme-line .select,
-.theme-line .typeahead {
-    .active {
-        font-size: 1em;
-        background-color: $gray-lighter;
-    }
-}
-
-.theme-line button.form-control.placeholder {
-    color: $input-color-placeholder;
-}
-
-.theme-line .summary-pojo-list > ul.dropdown-menu {
-    width: 100%;
-    max-width: none;
-}
-
-.tooltip {
-  word-wrap: break-word;
-}
-
-.theme-line ul.dropdown-menu {
-    min-width: 120px;
-    max-width: 280px;
-    max-height: 20em;
-    overflow: auto;
-    overflow-x: hidden;
-    outline-style: none;
-
-    li > a {
-        display: block;
-
-        //cursor: default;
-        padding: 3px 10px;
-
-        overflow: hidden;
-        white-space: nowrap;
-        text-overflow: ellipsis;
-
-        i {
-            float: right;
-            color: $brand-primary;
-            background-color: transparent;
-            line-height: $line-height-base;
-            margin-left: 5px;
-            margin-right: 0;
-        }
-    }
-
-    li.divider {
-        margin: 3px 0;
-    }
-}
-
-.theme-line .border-left .sidebar-nav {
-    padding-left: 15px;
-}
-
-.theme-line .suggest {
-    padding: 5px;
-    display: inline-block;
-    font-size: 12px;
-}
-
-.theme-line header {
-    border-bottom: 8px solid $ignite-border-bottom-color;
-
-    p {
-        color: $ignite-header-color;
-    }
-}
-
-.header .nav.navbar-nav.pull-right > li > a {
-    padding-right: 0;
-}
-
-.header .title {
-    margin: 20px 0 5px 0;
-    padding: 0 15px;
-
-    font-size: 1.4em;
-}
-
-.header .nav.navbar-nav .not-link {
-    padding: 15px;
-    display: inline-block;
-}
-
-.nav > li {
-    > a {
-        color: $navbar-default-link-color
-    }
-    > a:hover {
-        color: $link-hover-color
-    }
-    > a.active {
-        color: $link-color
-    }
-}
-
-.theme-line header .navbar-nav a {
-    line-height: 25px;
-    font-size: 18px;
-}
-
-.theme-line .section-right {
-    padding-left: 30px;
-}
-
-.body-overlap .main-content {
-    margin-top: 30px;
-}
-
-.body-box .main-content,
-.body-overlap .main-content {
-    padding: 30px;
-    box-shadow: 0 0 0 1px $ignite-border-color;
-    background-color: $ignite-background-color;
-}
-
-body {
-    font-weight: 400;
-}
-
-h1, h2, h3, h4, h5, h6 {
-    font-weight: 700;
-    margin-bottom: 10px;
-}
-
-.container-footer {
-    margin-top: 20px;
-    margin-bottom: 20px;
-
-    p {
-        font-size: 12px;
-        margin-bottom: 0;
-    }
-}
-
-/* Modal */
-.modal {
-    display: block;
-    overflow: hidden;
-}
-
-.modal .close {
-    position: absolute;
-    top: 10px;
-    right: 10px;
-    float: none;
-}
-
-.modal-header {
-    border-top-left-radius: 6px;
-    border-top-right-radius: 6px;
-}
-
-// Close icon
-.modal-header .close {
-    margin-right: -2px;
-}
-
-.modal .modal-dialog {
-    width: 650px;
-}
-
-.modal .modal-content {
-    background-color: $gray-lighter;
-
-    .input-tip {
-        padding-top: 1px;
-    }
-}
-
-.modal .modal-content .modal-header {
-    background-color: $ignite-background-color;
-    text-align: center;
-    color: $ignite-header-color;
-    padding: 15px 25px 15px 15px;
-}
-
-.modal .modal-content .modal-header h4 {
-    font-size: 22px;
-}
-
-.modal .modal-content .modal-footer {
-    margin-top: 0;
-}
-
-.modal-footer {
-    label {
-        float: left;
-        margin: 0;
-    }
-
-    .btn:last-child {
-        margin-right: 0;
-    }
-
-    .checkbox {
-        margin: 0;
-    }
-}
-
-.login-header {
-    margin-top: 0;
-    margin-bottom: 20px;
-    font-size: 2em;
-}
-
-.login-footer {
-    @extend .modal-footer;
-
-    padding-left: 0;
-    padding-right: 0;
-
-    .btn {
-        margin-right: 0;
-    }
-}
-
-.modal-body {
-    margin-left: 20px;
-    margin-right: 20px;
-}
-
-.modal-body-with-scroll {
-    max-height: 420px;
-    overflow-y: auto;
-    margin: 0;
-}
-
-.greedy {
-    min-height: 100%;
-    height: #{"calc(100vh - 270px)"};
-}
-
-.signin-greedy {
-    height: #{"calc(100vh - 300px)"};
-}
-
-@media (min-width: 768px) {
-    .navbar-nav > li > a {
-        padding: 0 15px;
-    }
-}
-
-.details-row {
-    padding: 0 5px;
-}
-
-.details-row, .settings-row {
-    display: block;
-    margin: 10px 0;
-
-    [class*="col-"] {
-        display: inline-block;
-        vertical-align: middle;
-        float: none;
-    }
-
-    input[type="checkbox"] {
-        line-height: 20px;
-        margin-right: 5px;
-    }
-
-    .checkbox label {
-        line-height: 20px !important;
-        vertical-align: middle;
-    }
-}
-
-.group-section {
-    margin-top: 20px;
-}
-
-.details-row:first-child {
-    margin-top: 0;
-
-    .group-section {
-        margin-top: 10px;
-    }
-}
-
-.details-row:last-child {
-    margin-bottom: 0;
-}
-
-.settings-row:first-child {
-    margin-top: 0;
-
-    .group-section {
-        margin-top: 0;
-    }
-}
-
-.settings-row:last-child {
-    margin-bottom: 0;
-}
-
-button, .btn {
-    margin-right: 5px;
-}
-
-i.btn {
-    margin-right: 0;
-}
-
-.btn {
-    padding: 3px 6px;
-
-    :focus {
-        //outline: none;
-        //border: 1px solid $btn-default-border;
-    }
-}
-
-.btn-group.pull-right {
-    margin-right: 0;
-}
-
-.btn-group {
-    margin-right: 5px;
-
-    > button, a.btn {
-        margin-right: 0;
-    }
-
-    button.btn + .btn {
-        margin-left: 0;
-    }
-
-    > .btn + .dropdown-toggle {
-        margin-right: 0;
-        padding: 3px 6px;
-        border-left-width: 0;
-    }
-}
-
-h1,
-h2,
-h3 {
-    user-select: none;
-    font-weight: normal;
-    /* Makes the vertical size of the text the same for all fonts. */
-    line-height: 1;
-}
-
-h3 {
-    font-size: 1.2em;
-    margin-top: 0;
-    margin-bottom: 1.5em;
-}
-
-.base-control {
-    text-align: left;
-    padding: 3px 3px;
-    height: $input-height;
-}
-
-.sql-name-input {
-    @extend .form-control;
-
-    width: auto;
-}
-
-.form-control {
-    @extend .base-control;
-
-    display: inline-block;
-
-    button {
-        text-align: left;
-    }
-}
-
-button.form-control {
-    display: block;
-    overflow: hidden;
-    white-space: nowrap;
-    text-overflow: ellipsis;
-}
-
-.theme-line .notebook-header {
-    border-color: $gray-lighter;
-
-    h1 {
-        padding: 0;
-        margin: 0;
-
-        height: 40px;
-
-        label {
-            overflow: hidden;
-            text-overflow: ellipsis;
-            white-space: nowrap;
-            margin-top: 5px;
-        }
-
-        .btn-group {
-            margin-top: -5px;
-            margin-left: 5px;
-        }
-
-        > i.btn {
-            float: right;
-            line-height: 30px;
-        }
-
-        input {
-            font-size: 22px;
-            height: 35px;
-        }
-
-        a.dropdown-toggle {
-            font-size: $font-size-base;
-            margin-right: 5px;
-        }
-    }
-}
-
-.theme-line .sql-notebooks {
-    li.custom > a {
-        color: $brand-info;
-        font-weight: bold;
-    }
-
-    li.custom > a:hover {
-        color: darken($brand-info, 15%);
-    }
-}
-
-.theme-line .paragraphs {
-    .panel-group .panel + .panel {
-        margin-top: 30px;
-    }
-
-    .btn-group {
-        margin-right: 0;
-    }
-
-    .sql-editor {
-        padding: 5px 0;
-
-        .ace_cursor {
-            opacity: 1;
-        }
-
-        .ace_hidden-cursors {
-            opacity: 1;
-        }
-
-        .ace_gutter-cell, .ace_folding-enabled > .ace_gutter-cell {
-            padding-right: 5px;
-        }
-    }
-
-    .sql-controls {
-        margin: 10px 0;
-        padding: 0 10px;
-    }
-
-    .sql-table-total {
-        padding: 0 10px;
-
-        label, b {
-            display: inline-block;
-
-            padding-top: 5px;
-
-            height: 27px;
-        }
-
-        margin-bottom: 10px;
-    }
-
-    .sql-table {
-        height: 400px;
-    }
-
-    table thead {
-        background-color: white;
-    }
-
-    .wrong-caches-filter {
-        text-align: center;
-        color: $ignite-placeholder-color;
-        height: 65px;
-        line-height: 65px;
-    }
-
-    .empty-caches {
-        text-align: center;
-        color: $ignite-placeholder-color;
-        height: 55px;
-        line-height: 55px;
-    }
-
-    .sql-error-result {
-        padding: 10px 0;
-
-        text-align: center;
-        color: $brand-primary;
-
-        border-top: 1px solid $ignite-border-color;
-    }
-
-    .sql-empty-result {
-        margin-top: 10px;
-        margin-bottom: 10px;
-        text-align: center;
-        color: $ignite-placeholder-color;
-    }
-
-    .sql-next {
-        float: right;
-
-        .disabled {
-            cursor: default;
-            text-decoration: none;
-        }
-
-        a {
-            margin-right: 5px;
-            margin-bottom: 5px;
-        }
-
-        i {
-            margin-top: 3px;
-            margin-right: 10px;
-        }
-    }
-}
-
-.theme-line .panel-heading {
-    padding: 5px 10px;
-    margin: 0;
-    cursor: pointer;
-    font-size: $font-size-large;
-    line-height: 24px;
-
-    label {
-        overflow: hidden;
-        text-overflow: ellipsis;
-        white-space: nowrap;
-        max-width: calc(100% - 85px);
-        cursor: pointer;
-    }
-
-    .btn-group {
-        vertical-align:top;
-        margin-left: 10px;
-
-        i { line-height: 18px; }
-    }
-
-    > i {
-        vertical-align: top;
-        line-height: 26px;
-        height: 26px;
-    }
-
-    .fa {
-        line-height: 26px;
-    }
-
-    .fa-floppy-o {
-        float: right;
-    }
-
-    .fa-chevron-circle-right, .fa-chevron-circle-down {
-        font-size: $font-size-base;
-        color: inherit;
-        float: left;
-    }
-
-    .fa-undo {
-        padding: 1px 6px;
-
-        font-size: 16px;
-    }
-
-    .fa-undo:hover {
-        padding: 0 5px;
-
-        border-radius: 5px;
-        border: thin dotted $ignite-darck-border-color;
-    }
-}
-
-.theme-line .panel-heading:hover {
-    text-decoration: underline;
-}
-
-.theme-line .panel-body {
-    padding: 20px;
-}
-
-.theme-line .main-content a.customize {
-    margin-left: 5px;
-}
-
-.theme-line .panel-collapse {
-    margin: 0;
-}
-
-.theme-line table.links {
-    table-layout: fixed;
-    border-collapse: collapse;
-
-    width: 100%;
-
-    label.placeholder {
-        text-align: center;
-        color: $ignite-placeholder-color;
-        width: 100%;
-    }
-
-    input[type="text"] {
-        font-weight: normal;
-    }
-
-    input[type="radio"] {
-        margin-left: 1px;
-        margin-right: 5px;
-    }
-
-    tbody {
-        border-left: 10px solid transparent;
-    }
-
-    tbody td:first-child {
-        overflow: hidden;
-        text-overflow: ellipsis;
-        white-space: nowrap;
-    }
-
-    tfoot > tr > td {
-        padding: 0;
-
-        .pagination {
-            margin: 10px 0;
-
-            > .active > a {
-                border-color: $table-border-color;
-                background-color: $gray-lighter;
-            }
-        }
-    }
-}
-
-.theme-line table.links-edit {
-    @extend table.links;
-
-    margin-top: 0;
-    margin-bottom: 5px;
-
-    label {
-        line-height: $input-height;
-    }
-
-    td {
-        padding-left: 0;
-    }
-}
-
-.theme-line table.links-edit-sub {
-    @extend table.links-edit;
-
-    margin-top: 0;
-    margin-bottom: 0;
-}
-
-.theme-line table.links-edit-details {
-    @extend table.links;
-
-    margin-bottom: 10px;
-
-    label {
-        line-height: $input-height;
-        color: $ignite-header-color;
-    }
-
-    td {
-        padding: 0;
-
-        .input-tip {
-            padding: 0;
-        }
-    }
-}
-
-.theme-line table.admin {
-    tr:hover {
-        cursor: default;
-    }
-
-    thead {
-        .pagination {
-            margin: 0;
-        }
-    }
-
-    thead > tr th.header {
-        padding: 0 0 10px;
-
-        div {
-            padding: 0;
-        }
-
-        input[type="text"] {
-            font-weight: normal;
-        }
-    }
-
-    margin-bottom: 10px;
-
-    label {
-        line-height: $input-height;
-        color: $ignite-header-color;
-    }
-
-    thead > tr th, td {
-        padding: 10px 10px;
-
-        .input-tip {
-            padding: 0;
-        }
-    }
-
-    tfoot > tr > td {
-        padding: 0;
-    }
-
-    .pagination {
-        margin: 10px 0;
-        font-weight: normal;
-
-        > .active > a {
-            border-color: $table-border-color;
-            background-color: $gray-lighter;
-        }
-    }
-}
-
-.admin-summary {
-    padding-bottom: 10px;
-}
-
-.import-domain-model-wizard-page {
-    margin: 15px;
-}
-
-.scrollable-y {
-    overflow-x: hidden;
-    overflow-y: auto;
-}
-
-.theme-line table.metadata {
-    margin-bottom: 10px;
-
-    tr:hover {
-        cursor: default;
-    }
-
-    thead > tr {
-        label {
-            font-weight: bold;
-        }
-
-        input[type="checkbox"] {
-            cursor: pointer;
-        }
-    }
-
-    thead > tr th.header {
-        padding: 0 0 10px;
-
-        .pull-right {
-            padding: 0;
-        }
-
-        input[type="checkbox"] {
-            cursor: pointer;
-        }
-
-        input[type="text"] {
-            font-weight: normal;
-        }
-    }
-
-    > thead > tr > th {
-        padding: 5px 0 5px 5px !important;
-    }
-
-    tbody > tr > td {
-        padding: 0;
-    }
-}
-
-.td-ellipsis {
-    overflow: hidden;
-    text-overflow: ellipsis;
-    white-space: nowrap;
-}
-
-.table-modal-striped {
-    width: 100%;
-
-    > tbody > tr {
-        border-bottom: 2px solid $ignite-border-color;
-
-        input[type="checkbox"] {
-            cursor: pointer;
-        }
-    }
-
-    > tbody > tr > td {
-        padding: 5px 0 5px 5px !important;
-    }
-}
-
-.theme-line table.sql-results {
-    margin: 0;
-
-    td {
-        padding: 3px 6px;
-    }
-
-    > thead > tr > td {
-        padding: 3px 0;
-    }
-
-    thead > tr > th {
-        padding: 3px 6px;
-
-        line-height: $input-height;
-    }
-
-    tfoot > tr > td {
-        padding: 0;
-
-        .pagination {
-            margin: 10px 0 0 0;
-
-            > .active > a {
-                border-color: $table-border-color;
-                background-color: $gray-lighter;
-            }
-        }
-    }
-}
-
-.affix {
-    z-index: 910;
-    background-color: white;
-
-    hr {
-        margin: 0;
-    }
-}
-
-.affix.padding-top-dflt {
-    hr {
-        margin-top: 10px;
-    }
-}
-
-.affix + .bs-affix-fix {
-    height: 78px;
-}
-
-.panel-details {
-    margin-top: 5px;
-    padding: 10px 5px;
-
-    border-radius: 5px;
-    border: thin dotted $ignite-border-color;
-}
-
-.panel-details-noborder {
-    margin-top: 5px;
-    padding: 10px 5px;
-}
-
-.group {
-    border-radius: 5px;
-    border: thin dotted $ignite-border-color;
-
-    text-align: left;
-
-    hr {
-        margin: 7px 0;
-    }
-}
-
-.group-legend {
-    margin: -10px 5px 0 10px;
-    overflow: visible;
-    position: relative;
-
-    label {
-        padding: 0 5px;
-        background: white;
-    }
-}
-
-.group-legend-btn {
-    background: white;
-    float: right;
-    line-height: 20px;
-    padding: 0 5px 0 5px;
-}
-
-.group-content {
-    margin: 10px;
-
-    table {
-        width: 100%;
-    }
-}
-
-.group-content-empty {
-    color: $input-color-placeholder;
-
-    padding: 10px 0;
-    position: relative;
-
-    text-align: center;
-}
-
-.content-not-available {
-    min-height: 28px;
-
-    margin-right: 20px;
-
-    border-radius: 5px;
-    border: thin dotted $ignite-border-color;
-
-    padding: 0;
-
-    color: $input-color-placeholder;
-    display: table;
-    width: 100%;
-    height: 26px;
-
-    label {
-        display: table-cell;
-        text-align: center;
-        vertical-align: middle;
-    }
-}
-
-.tooltip > .tooltip-inner {
-    text-align: left;
-    border: solid 1px #ccc;
-}
-
-.popover-footer {
-    margin: 0; // reset heading margin
-    padding: 8px 14px;
-    font-size: $font-size-base;
-    color: $input-color-placeholder;
-    background-color: $popover-title-bg;
-    border-top: 1px solid darken($popover-title-bg, 5%);
-    border-radius: 0 0 ($border-radius-large - 1) ($border-radius-large - 1);
-}
-
-.popover-content {
-    padding: 5px;
-}
-
-.popover:focus {
-    outline: none;
-    border: 1px solid $btn-default-border;
-}
-
-.theme-line .popover.settings {
-    .close {
-        position: absolute;
-        top: 5px;
-        right: 5px;
-    }
-}
-
-.theme-line .popover.cache-metadata {
-    @extend .popover.settings;
-
-    z-index: 1030;
-    min-width: 305px;
-    max-width: 450px;
-
-    .popover-title {
-        color: black;
-
-        line-height: 27px;
-
-        padding: 3px 5px 3px 10px;
-
-        white-space: nowrap;
-        overflow: hidden;
-        -o-text-overflow: ellipsis;
-        text-overflow: ellipsis;
-
-        .close {
-            float: right;
-            top: 0;
-            right: 0;
-            position: relative;
-            margin-left: 10px;
-            line-height: 27px;
-        }
-    }
-
-    > .popover-content {
-        overflow: auto;
-
-        white-space: nowrap;
-
-        min-height: 400px;
-        max-height: 400px;
-
-        .content-empty {
-            display: block;
-            text-align: center;
-            line-height: 380px;
-
-            color: $input-color-placeholder;
-        }
-    }
-
-    .clickable { cursor: pointer; }
-}
-
-.theme-line .popover.summary-project-structure {
-    @extend .popover.settings;
-
-    z-index: 1030;
-    min-width: 305px;
-
-    .popover-title {
-        color: black;
-
-        line-height: 27px;
-
-        padding: 3px 5px 3px 10px;
-
-        white-space: nowrap;
-        overflow: hidden;
-        -o-text-overflow: ellipsis;
-        text-overflow: ellipsis;
-
-        .close {
-            float: right;
-            top: 0;
-            right: 0;
-            position: relative;
-            margin-left: 10px;
-            line-height: 27px;
-        }
-    }
-
-    > .popover-content {
-        overflow: auto;
-
-        white-space: nowrap;
-
-        min-height: 300px;
-        max-height: 300px;
-    }
-}
-
-.theme-line .popover.validation-error {
-    max-width: 400px;
-    color: $brand-primary;
-    background: white;
-    border: 1px solid $brand-primary;
-
-    &.right > .arrow {
-        border-right-color: $brand-primary;
-    }
-
-    .close {
-        vertical-align: middle;
-    }
-}
-
-label {
-    font-weight: normal;
-    margin-bottom: 0;
-}
-
-.form-horizontal .checkbox {
-    padding-top: 0;
-    min-height: 0;
-}
-
-.input-tip {
-    display: block;
-    overflow: hidden;
-    position: relative;
-}
-
-.labelHeader {
-    font-weight: bold;
-    text-transform: capitalize;
-}
-
-.labelField {
-    float: left;
-    margin-right: 5px;
-}
-
-.labelFormField {
-    float: left;
-    line-height: $input-height;
-}
-
-.labelLogin {
-    margin-right: 10px;
-}
-
-.form-horizontal .form-group {
-    margin: 0;
-}
-
-.form-horizontal .has-feedback .form-control-feedback {
-    right: 0;
-}
-
-.tipField {
-    float: right;
-    line-height: $input-height;
-    margin-left: 5px;
-}
-
-.tipLabel {
-    font-size: $font-size-base;
-    margin-left: 5px;
-}
-
-.fieldSep {
-    float: right;
-    line-height: $input-height;
-    margin: 0 5px;
-}
-
-.fieldButton {
-    float: right;
-    margin-left: 5px;
-    margin-right: 0;
-}
-
-.fa {
-    cursor: pointer;
-}
-
-.fa-cursor-default {
-    cursor: default !important;
-}
-
-.fa-remove {
-    color: $brand-primary;
-}
-
-.fa-chevron-circle-down {
-    color: $brand-primary;
-    margin-right: 5px;
-}
-
-.fa-chevron-circle-right {
-    color: $brand-primary;
-    margin-right: 5px;
-}
-
-.fa-question-circle {
-    cursor: default;
-}
-
-label.required:after {
-    color: $brand-primary;
-    content: ' *';
-    display: inline;
-}
-
-.blank {
-    visibility: hidden;
-}
-
-.alert {
-    outline: 0;
-    padding: 10px;
-    position: fixed;
-    z-index: 1050;
-    margin: 20px;
-    max-width: 700px;
-
-    &.top-right {
-        top: 60px;
-        right: 0;
-
-        .close {
-            padding-left: 10px;
-        }
-    }
-
-    .alert-icon {
-        padding-right: 10px;
-        font-size: 16px;
-    }
-
-    .alert-title {
-        color: $text-color;
-    }
-
-    .close {
-        margin-right: 0;
-        line-height: 19px;
-    }
-}
-
-.summary-tabs {
-    margin-top: 0.65em;
-}
-
-.summary-tab {
-    img {
-        margin-right: 5px;
-        height: 16px;
-        width: 16px;
-        float: left;
-    }
-}
-
-input[type="number"]::-webkit-outer-spin-button,
-input[type="number"]::-webkit-inner-spin-button {
-    -webkit-appearance: none;
-    margin: 0;
-}
-
-input[type="number"] {
-    -moz-appearance: textfield;
-}
-
-input.ng-dirty.ng-invalid, button.ng-dirty.ng-invalid {
-    border-color: $ignite-invalid-color;
-
-    :focus {
-        border-color: $ignite-invalid-color;
-    }
-}
-
-.form-control-feedback {
-    display: inline-block;
-    color: $brand-primary;
-    line-height: $input-height;
-    pointer-events: initial;
-}
-
-.theme-line .nav-tabs > li > a {
-    padding: 5px 5px;
-    color: $ignite-header-color;
-}
-
-.viewedUser {
-    text-align: center;
-    background-color: $brand-warning;
-}
-
-a {
-    cursor: pointer;
-}
-
-.st-sort-ascent:after {
-    content: '\25B2';
-}
-
-.st-sort-descent:after {
-    content: '\25BC';
-}
-
-th[st-sort] {
-    cursor: pointer;
-}
-
-.panel {
-    margin-bottom: 0;
-}
-
-.panel-group {
-    margin-bottom: 0;
-}
-
-.panel-group .panel + .panel {
-    margin-top: 20px;
-}
-
-.section {
-    margin-top: 20px;
-}
-
-.section-top {
-    width: 100%;
-    margin-top: 10px;
-    margin-bottom: 20px;
-}
-
-.advanced-options {
-    @extend .section;
-    margin-bottom: 20px;
-
-    i {
-        font-size: 16px;
-    }
-}
-
-.modal-advanced-options {
-    @extend .advanced-options;
-    margin-top: 10px;
-    margin-bottom: 10px;
-}
-
-.margin-left-dflt {
-    margin-left: 10px;
-}
-
-.margin-top-dflt {
-    margin-top: 10px;
-}
-
-.margin-top-dflt-2x {
-    margin-top: 20px;
-}
-
-.margin-bottom-dflt {
-    margin-bottom: 10px;
-}
-
-.margin-dflt {
-    margin-top: 10px;
-    margin-bottom: 10px;
-}
-
-.padding-top-dflt {
-    padding-top: 10px;
-}
-
-.padding-left-dflt {
-    padding-left: 10px;
-}
-
-.padding-bottom-dflt {
-    padding-bottom: 10px;
-}
-
-.padding-dflt {
-    padding-top: 10px;
-    padding-bottom: 10px;
-}
-
-.agent-download {
-    padding: 10px 10px 10px 20px;
-}
-
-.ace_content {
-    padding-left: 5px;
-}
-
-.ace_hidden-cursors {
-    opacity: 0;
-}
-
-.ace_cursor {
-    opacity: 0;
-}
-
-.ace_editor {
-    margin: 10px 5px 10px 0;
-
-    .ace_gutter {
-        background: transparent !important;
-        border: 1px $ignite-border-color;
-        border-right-style: solid;
-    }
-
-    .ace_gutter-cell, .ace_folding-enabled > .ace_gutter-cell {
-        padding-left: 0.65em;
-    }
-}
-
-.preview-highlight-1 {
-    position: absolute;
-    background-color: #f7faff;
-    z-index: 20;
-}
-
-.preview-highlight-2 {
-    position: absolute;
-    background-color: #f0f6ff;
-    z-index: 21;
-}
-
-.preview-highlight-3 {
-    position: absolute;
-    background-color: #e8f2ff;
-    z-index: 22;
-}
-
-.preview-highlight-4 {
-    position: absolute;
-    background-color: #e1eeff;
-    z-index: 23;
-}
-
-.preview-highlight-5 {
-    position: absolute;
-    background-color: #DAEAFF;
-    z-index: 24;
-}
-
-.preview-highlight-6 {
-    position: absolute;
-    background-color: #D2E5FF;
-    z-index: 25;
-}
-
-.preview-highlight-7 {
-    position: absolute;
-    background-color: #CBE1FF;
-    z-index: 26;
-}
-
-.preview-highlight-8 {
-    position: absolute;
-    background-color: #C3DDFF;
-    z-index: 27;
-}
-
-.preview-highlight-9 {
-    position: absolute;
-    background-color: #BCD9FF;
-    z-index: 28;
-}
-
-.preview-highlight-10 {
-    position: absolute;
-    background-color: #B5D5FF;
-    z-index: 29;
-}
-
-.preview-panel {
-    min-height: 28px;
-
-    margin-left: 20px;
-
-    border-radius: 5px;
-    border: thin dotted $ignite-border-color;
-
-    padding: 0;
-}
-
-.preview-legend {
-    top: -10px;
-    right: 20px;
-    position: absolute;
-    z-index: 900;
-
-    a {
-        background-color: white;
-        margin-left: 5px;
-        font-size: 0.9em;
-    }
-
-    .inactive {
-        color: $input-color-placeholder;
-    }
-}
-
-.preview-content-empty {
-    color: $input-color-placeholder;
-    display: table;
-    width: 100%;
-    height: 26px;
-
-    label {
-        display: table-cell;
-        text-align: center;
-        vertical-align: middle;
-    }
-}
-
-.chart-settings-link {
-    padding-left: 10px;
-    line-height: $input-height;
-
-    label, button {
-        margin-left: 5px;
-        margin-right: 0;
-    }
-
-    button.select-manual-caret {
-        padding-right: 3px;
-
-        .caret { margin-left: 3px; }
-    }
-
-    a, i {
-        font-size: $font-size-base;
-        color: $link-color !important;
-        margin-right: 5px;
-    }
-
-    div {
-        margin-left: 20px;
-        display: inline-block;
-    }
-}
-
-.chart-settings {
-    margin: 10px 5px 5px 5px !important;
-}
-
-.chart-settings-columns-list {
-    border: 1px solid $ignite-border-color;
-    list-style: none;
-    margin-bottom: 10px;
-    min-height: 30px;
-    max-height: 200px;
-    padding: 5px;
-
-    overflow: auto;
-
-    & > li {
-        float: left;
-    }
-
-    li:nth-child(even) {
-        margin-right: 0;
-    }
-
-    .fa-close {
-        margin-left: 10px;
-    }
-}
-
-.btn-chart-column {
-    border-radius: 3px;
-    font-size: 12px;
-    margin: 3px 3px;
-    padding: 1px 5px;
-    line-height: 1.5;
-    cursor: default;
-}
-
-.btn-chart-column-movable {
-    @extend .btn-chart-column;
-    cursor: move;
-}
-
-.btn-chart-column-agg-fx {
-    border: 0;
-    margin: 0 0 0 10px;
-}
-
-.dw-loading {
-    min-height: 100px;
-}
-
-.dw-loading > .dw-loading-body > .dw-loading-text {
-    left: -50%;
-}
-
-.dw-loading.dw-loading-overlay {
-    z-index: 1030;
-}
-
-.modal {
-    .dw-loading.dw-loading-overlay {
-        z-index: 9999;
-    }
-
-    .dw-loading-body {
-        left: 10%;
-    }
-}
-
-.panel-tip-container {
-    display: inline-block;
-}
-
-button.dropdown-toggle {
-    margin-right: 5px;
-}
-
-button.select-toggle {
-    position: relative;
-    padding-right: 15px;
-}
-
-button.select-toggle::after {
-    content: "";
-    border-top: 0.3em solid;
-    border-right: 0.3em solid transparent;
-    border-left: 0.3em solid transparent;
-    position: absolute;
-    right: 5px;
-    top: 50%;
-    vertical-align: middle;
-}
-
-// Prevent scroll bars from being hidden for OS X.
-::-webkit-scrollbar {
-    -webkit-appearance: none;
-}
-
-::-webkit-scrollbar:vertical {
-    width: 10px;
-}
-
-::-webkit-scrollbar:horizontal {
-    height: 10px;
-}
-
-::-webkit-scrollbar-thumb {
-    border-radius: 8px;
-    border: 2px solid white; /* should match background, can't be transparent */
-    background-color: rgba(0, 0, 0, .5);
-}
-
-::-webkit-scrollbar-track {
-    background-color: white;
-    border-radius: 8px;
-}
-
-treecontrol.tree-classic {
-    > ul > li {
-        padding: 0;
-    }
-
-    li {
-        padding-left: 15px;
-    }
-
-    li.tree-expanded i.tree-branch-head.fa, li.tree-collapsed i.tree-branch-head.fa, li.tree-leaf i.tree-branch-head.fa, .tree-label i.fa {
-        background: none no-repeat;
-        padding: 1px 5px 1px 1px;
-    }
-
-    li.tree-leaf i.tree-leaf-head {
-        background: none no-repeat !important;
-        padding: 0 !important;
-    }
-
-    li .tree-selected {
-        background-color: white;
-        font-weight: normal;
-    }
-
-    span {
-        margin-right: 10px;
-    }
-}
-
-.docs-content {
-    .affix {
-        border-bottom: 1px solid $gray-lighter;
-    }
-
-    min-height: 100px;
-}
-
-.carousel-caption {
-    position: relative;
-    left: auto;
-    right: auto;
-
-    margin-top: 10px;
-
-    h3 {
-        margin-bottom: 10px;
-    }
-}
-
-.carousel-control {
-    font-size: 20px;
-    z-index: 16;
-
-    // Toggles
-    .fa-chevron-left,.fa-chevron-right {
-        position: absolute;
-        bottom: 28px;
-        margin-top: -10px;
-        z-index: 16;
-        display: inline-block;
-        margin-left: -10px;
-    }
-
-    .fa-chevron-left {
-        left: 90%;
-        margin-left: -10px;
-    }
-
-    .fa-chevron-right {
-        right: 90%;
-        margin-right: -10px;
-    }
-}
-
-.carousel-control.left {
-    background-image: none;
-}
-
-.carousel-control.right {
-    background-image: none;
-}
-
-.getting-started-puzzle {
-    margin-left: 20px;
-}
-
-.getting-started {
-    margin: 15px 15px 300px;
-}
-
-.getting-started-demo {
-    color: $brand-info;
-}
-
-.home-panel {
-    border-radius: 5px;
-    border: thin dotted $panel-default-border;
-    background-color: $panel-default-heading-bg;
-
-    margin-top: 20px;
-    padding: 10px;
-}
-
-.home {
-    min-height: 880px;
-    padding: 20px;
-
-    @media(min-width: 992px) {
-        min-height: 450px;
-    }
-}
-
-.additional-filter {
-    input[type="checkbox"] {
-        position: absolute;
-        margin-top: 8px;
-    }
-
-    a {
-        font-weight: normal;
-        padding-left: 20px;
-        float: none;
-    }
-}
-
-.grid {
-    .ui-grid-header-cell .ui-grid-cell-contents {
-        text-align: center;
-
-        > span:not(.ui-grid-header-cell-label) {
-            position: absolute;
-            right: -3px;
-        }
-    }
-
-    .ui-grid-cell .ui-grid-cell-contents {
-        text-align: center;
-        white-space: pre;
-
-        > i.fa {
-            cursor: default;
-        }
-    }
-
-    .ui-grid-column-menu-button {
-        right: -3px;
-    }
-
-    .ui-grid-menu-button {
-        margin-top: -1px;
-    }
-
-    .ui-grid-column-menu-button-last-col {
-        margin-right: 0
-    }
-
-    .no-rows {
-        .center-container {
-            background: white;
-
-            .centered > div {
-                display: inline-block;
-                padding: 10px;
-
-                opacity: 1;
-
-                background-color: #f5f5f5;
-                border-radius: 6px;
-                border: 1px solid $ignite-darck-border-color;
-            }
-        }
-    }
-}
-
-.cell-right .ui-grid-cell-contents {
-    text-align: right !important;
-}
-
-.cell-left .ui-grid-cell-contents {
-    text-align: left !important;
-}
-
-.grid.ui-grid {
-    border-left-width: 0;
-    border-right-width: 0;
-    border-bottom-width: 0;
-}
-
-.summary-tabs {
-    .nav-tabs > li:first-child,
-    .nav-tabs > li:first-child.active {
-        & > a,
-        & > a:focus,
-        & > a:hover {
-            border-left: none;
-            border-top-left-radius: 0;
-        }
-    }
-}
-
-.ribbon-wrapper {
-    width: 150px;
-    height: 150px;
-    position: absolute;
-    overflow: hidden;
-    top: 0;
-    z-index: 1001;
-    pointer-events: none;
-}
-
-.ribbon-wrapper.right {
-    right: 0;
-}
-
-.ribbon {
-    position: absolute;
-    top: 42px;
-    width: 200px;
-    padding: 1px 0;
-    color: $btn-primary-color;
-    background: $btn-primary-border;
-
-    -moz-box-shadow: 0 0 10px rgba(0,0,0,0.5);
-    -webkit-box-shadow: 0 0 10px rgba(0,0,0,0.5);
-    box-shadow: 0 0 10px rgba(0,0,0,0.5);
-
-    right: -42px;
-    -moz-transform: rotate(45deg);
-    -webkit-transform: rotate(45deg);
-    -o-transform: rotate(45deg);
-    -ms-transform: rotate(45deg);
-    transform: rotate(45deg);
-
-    > label {
-        display: block;
-        padding: 1px 0;
-        height: 24px;
-        line-height: 18px;
-
-        text-align: center;
-        text-decoration: none;
-        font-family: 'Roboto Slab', sans-serif;
-        font-size: 20px;
-        font-weight: 500;
-
-        border: 1px solid rgba(255,255,255,0.3);
-
-        -moz-text-shadow: 0 0 10px rgba(0,0,0,0.31);
-        -webkit-text-shadow: 0 0 10px rgba(0,0,0,0.31);
-        text-shadow: 0 0 10px rgba(0,0,0,0.31);
-    }
-}
-
-html,body,.splash-screen {
-    width: 100%;
-    height: 100%;
-}
-
-.splash {
-    position: fixed;
-    bottom: 0;
-    left: 0;
-    right: 0;
-    top: 0;
-    opacity: 1;
-    background-color: white;
-    z-index: 99999;
-
-    .splash-wrapper {
-        display: inline-block;
-        vertical-align: middle;
-        position: relative;
-        width: 100%;
-    }
-
-    .splash-wellcome {
-        font-size: 18px;
-        margin: 20px 0;
-        text-align: center;
-    }
-}
-
-.splash:before {
-  content: '';
-  display: inline-block;
-  height: 100%;
-  vertical-align: middle;
-}
-
-.spinner {
-    margin: 0 auto;
-    width: 100px;
-    text-align: center;
-
-    > div {
-        width: 18px;
-        height: 18px;
-        margin: 0 5px;
-        border-radius: 100%;
-        display: inline-block;
-        -webkit-animation: sk-bouncedelay 1.4s infinite ease-in-out both;
-        animation: sk-bouncedelay 1.4s infinite ease-in-out both;
-        background-color: $brand-primary;
-    }
-
-    .bounce1 {
-        -webkit-animation-delay: -0.32s;
-        animation-delay: -0.32s;
-    }
-
-    .bounce2 {
-        -webkit-animation-delay: -0.16s;
-        animation-delay: -0.16s;
-    }
-}
-
-@-webkit-keyframes sk-bouncedelay {
-    0%, 80%, 100% {
-        -webkit-transform: scale(0)
-    }
-    40% {
-        -webkit-transform: scale(1.0)
-    }
-}
-
-@keyframes sk-bouncedelay {
-    0%, 80%, 100% {
-        -webkit-transform: scale(0);
-        transform: scale(0);
-    }
-    40% {
-        -webkit-transform: scale(1.0);
-        transform: scale(1.0);
-    }
-}
-
-[ng\:cloak], [ng-cloak], [data-ng-cloak], [x-ng-cloak], .ng-cloak, .x-ng-cloak {
-    display: none !important;
-}
-
-.nvd3 .nv-axis .nv-axisMaxMin text {
-    font-weight: normal; /* Here the text can be modified*/
-}
-
-[ng-hide].ng-hide-add.ng-hide-animate {
-    display: none;
-}
-
-[ng-show].ng-hide-add.ng-hide-animate {
-    display: none;
-}
-
-@media only screen and (max-width: 767px) {
-    .container{
-        padding: 0 $padding-small-horizontal;
-    }
-}
-
-.domains-import-dialog {
-    .modal-body {
-        height: 325px;
-        margin: 0;
-        padding: 0;
-    }
-}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/src/main/js/public/stylesheets/variables.scss
----------------------------------------------------------------------
diff --git a/modules/web-console/src/main/js/public/stylesheets/variables.scss b/modules/web-console/src/main/js/public/stylesheets/variables.scss
deleted file mode 100644
index 8500eac..0000000
--- a/modules/web-console/src/main/js/public/stylesheets/variables.scss
+++ /dev/null
@@ -1,28 +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 "bootstrap-variables";
-
-$logo-path: "/images/logo.png";
-$input-height: 28px;
-$ignite-placeholder-color: #999999;
-$ignite-border-color: #ddd;
-$ignite-darck-border-color: #aaa;
-$ignite-border-bottom-color: $brand-primary;
-$ignite-background-color: #fff;
-$ignite-header-color: #555;
-$ignite-invalid-color: $brand-primary;

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/src/main/js/serve.js
----------------------------------------------------------------------
diff --git a/modules/web-console/src/main/js/serve.js b/modules/web-console/src/main/js/serve.js
deleted file mode 100644
index 891855c..0000000
--- a/modules/web-console/src/main/js/serve.js
+++ /dev/null
@@ -1,116 +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.
- */
-
-'use strict';
-
-const http = require('http'),
-    https = require('https'),
-    path = require('path');
-
-/**
- * Event listener for HTTP server "error" event.
- */
-const _onError = (port, 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.
- */
-const _onListening = (addr) => {
-    var bind = typeof addr === 'string' ? 'pipe ' + addr : 'port ' + addr.port;
-
-    console.log('Start listening on ' + bind);
-};
-
-const igniteModules = (process.env.IGNITE_MODULES && path.relative(__dirname, process.env.IGNITE_MODULES)) || './ignite_modules';
-
-const fireUp = require('fire-up').newInjector({
-    basePath: __dirname,
-    modules: [
-        './serve/**/*.js',
-        `${igniteModules}/**/*.js`
-    ]
-});
-
-Promise.all([fireUp('settings'), fireUp('app'), fireUp('agent-manager'), fireUp('browser-manager')])
-    .then((values) => {
-        const settings = values[0];
-        const app = values[1];
-        const agentMgr = values[2];
-        const browserMgr = values[3];
-
-        // Start rest server.
-        const server = settings.server.SSLOptions
-            ? https.createServer(settings.server.SSLOptions) : http.createServer();
-
-        server.listen(settings.server.port);
-        server.on('error', _onError.bind(null, settings.server.port));
-        server.on('listening', _onListening.bind(null, server.address()));
-
-        app.listen(server);
-        browserMgr.attach(server);
-
-        // Start legacy agent server for reject connection with message.
-        if (settings.agent.legacyPort) {
-            const agentLegacySrv = settings.agent.SSLOptions
-                ? https.createServer(settings.agent.SSLOptions) : http.createServer();
-
-            agentLegacySrv.listen(settings.agent.legacyPort);
-            agentLegacySrv.on('error', _onError.bind(null, settings.agent.legacyPort));
-            agentLegacySrv.on('listening', _onListening.bind(null, agentLegacySrv.address()));
-
-            agentMgr.attachLegacy(agentLegacySrv);
-        }
-
-        // Start agent server.
-        const agentServer = settings.agent.SSLOptions
-            ? https.createServer(settings.agent.SSLOptions) : http.createServer();
-
-        agentServer.listen(settings.agent.port);
-        agentServer.on('error', _onError.bind(null, settings.agent.port));
-        agentServer.on('listening', _onListening.bind(null, agentServer.address()));
-
-        agentMgr.attach(agentServer);
-
-        // Used for automated test.
-        if (process.send)
-            process.send('running');
-    }).catch((err) => {
-        console.error(err);
-
-        process.exit(1);
-    });

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/src/main/js/serve/agent.js
----------------------------------------------------------------------
diff --git a/modules/web-console/src/main/js/serve/agent.js b/modules/web-console/src/main/js/serve/agent.js
deleted file mode 100644
index a529e94..0000000
--- a/modules/web-console/src/main/js/serve/agent.js
+++ /dev/null
@@ -1,714 +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.
- */
-
-'use strict';
-
-// Fire me up!
-
-/**
- * Module interaction with agents.
- */
-module.exports = {
-    implements: 'agent-manager',
-    inject: ['require(lodash)', 'require(ws)', 'require(fs)', 'require(path)', 'require(jszip)', 'require(socket.io)', 'settings', 'mongo']
-};
-
-/**
- * @param _
- * @param fs
- * @param ws
- * @param path
- * @param JSZip
- * @param socketio
- * @param settings
- * @param mongo
- * @returns {AgentManager}
- */
-module.exports.factory = function(_, ws, fs, path, JSZip, socketio, settings, mongo) {
-    /**
-     *
-     */
-    class Command {
-        /**
-         * @param {Boolean} demo Is need run command on demo node.
-         * @param {String} name Command name.
-         */
-        constructor(demo, name) {
-            this._demo = demo;
-
-            /**
-             * Command name.
-             * @type {String}
-             */
-            this._name = name;
-
-            /**
-             * Command parameters.
-             * @type {Array.<String>}
-             */
-            this._params = [];
-        }
-
-        /**
-         * Add parameter to command.
-         * @param {string} key Parameter key.
-         * @param {Object} value Parameter value.
-         * @returns {Command}
-         */
-        addParam(key, value) {
-            this._params.push({key, value});
-
-            return this;
-        }
-    }
-
-    /**
-     * Connected agent descriptor.
-     */
-    class Agent {
-        /**
-         * @param {socketIo.Socket} socket - Agent socket for interaction.
-         */
-        constructor(socket) {
-            /**
-             * Agent socket for interaction.
-             *
-             * @type {socketIo.Socket}
-             * @private
-             */
-            this._socket = socket;
-        }
-
-        /**
-         * Send message to agent.
-         *
-         * @this {Agent}
-         * @param {String} event Command name.
-         * @param {Object} data Command params.
-         * @param {Function} [callback] on finish
-         */
-        _emit(event, data, callback) {
-            if (!this._socket.connected) {
-                if (callback)
-                    callback('org.apache.ignite.agent.AgentException: Connection is closed');
-
-                return;
-            }
-
-            this._socket.emit(event, data, callback);
-        }
-
-        /**
-         * Send message to agent.
-         *
-         * @param {String} event - Event name.
-         * @param {Object?} data - Transmitted data.
-         * @returns {Promise}
-         */
-        executeAgent(event, data) {
-            return new Promise((resolve, reject) =>
-                this._emit(event, data, (error, res) => {
-                    if (error)
-                        return reject(error);
-
-                    resolve(res);
-                })
-            );
-        }
-
-        /**
-         * Execute rest request on node.
-         *
-         * @param {Command} cmd - REST command.
-         * @return {Promise}
-         */
-        executeRest(cmd) {
-            const params = {cmd: cmd._name};
-
-            for (const param of cmd._params)
-                params[param.key] = param.value;
-
-            return new Promise((resolve, reject) => {
-                this._emit('node:rest', {uri: 'ignite', params, demo: cmd._demo, method: 'GET'}, (error, res) => {
-                    if (error)
-                        return reject(new Error(error));
-
-                    error = res.error;
-
-                    const code = res.code;
-
-                    if (code === 401)
-                        return reject(new Error('Agent failed to authenticate in grid. Please check agent\'s login and password or node port.'));
-
-                    if (code !== 200)
-                        return reject(new Error(error || 'Failed connect to node and execute REST command.'));
-
-                    try {
-                        const msg = JSON.parse(res.data);
-
-                        if (msg.successStatus === 0)
-                            return resolve(msg.response);
-
-                        if (msg.successStatus === 2)
-                            return reject(new Error('Agent failed to authenticate in grid. Please check agent\'s login and password or node port.'));
-
-                        reject(new Error(msg.error));
-                    }
-                    catch (e) {
-                        return reject(e);
-                    }
-                });
-            });
-        }
-
-        /**
-         * @param {String} driverPath
-         * @param {String} driverClass
-         * @param {String} url
-         * @param {Object} info
-         * @returns {Promise} Promise on list of tables (see org.apache.ignite.schema.parser.DbTable java class)
-         */
-        metadataSchemas(driverPath, driverClass, url, info) {
-            return this.executeAgent('schemaImport:schemas', {driverPath, driverClass, url, info});
-        }
-
-        /**
-         * @param {String} driverPath
-         * @param {String} driverClass
-         * @param {String} url
-         * @param {Object} info
-         * @param {Array} schemas
-         * @param {Boolean} tablesOnly
-         * @returns {Promise} Promise on list of tables (see org.apache.ignite.schema.parser.DbTable java class)
-         */
-        metadataTables(driverPath, driverClass, url, info, schemas, tablesOnly) {
-            return this.executeAgent('schemaImport:metadata', {driverPath, driverClass, url, info, schemas, tablesOnly});
-        }
-
-        /**
-         * @returns {Promise} Promise on list of jars from driver folder.
-         */
-        availableDrivers() {
-            return this.executeAgent('schemaImport:drivers');
-        }
-
-        /**
-         *
-         * @param {Boolean} demo Is need run command on demo node.
-         * @param {Boolean} attr Get attributes, if this parameter has value true. Default value: true.
-         * @param {Boolean} mtr Get metrics, if this parameter has value true. Default value: false.
-         * @returns {Promise}
-         */
-        topology(demo, attr, mtr) {
-            const cmd = new Command(demo, 'top')
-                .addParam('attr', attr !== false)
-                .addParam('mtr', !!mtr);
-
-            return this.executeRest(cmd);
-        }
-
-        /**
-         *
-         * @param {Boolean} demo Is need run command on demo node.
-         * @param {String} cacheName Cache name.
-         * @param {String} query Query.
-         * @param {int} pageSize Page size.
-         * @returns {Promise}
-         */
-        fieldsQuery(demo, cacheName, query, pageSize) {
-            const cmd = new Command(demo, 'qryfldexe')
-                .addParam('cacheName', cacheName)
-                .addParam('qry', query)
-                .addParam('pageSize', pageSize);
-
-            return this.executeRest(cmd);
-        }
-
-        /**
-         *
-         * @param {Boolean} demo Is need run command on demo node.
-         * @param {String} cacheName Cache name.
-         * @param {int} pageSize Page size.
-         * @returns {Promise}
-         */
-        scan(demo, cacheName, pageSize) {
-            const cmd = new Command(demo, 'qryscanexe')
-                .addParam('cacheName', cacheName)
-                .addParam('pageSize', pageSize);
-
-            return this.executeRest(cmd);
-        }
-
-        /**
-         * @param {Boolean} demo Is need run command on demo node.
-         * @param {int} queryId Query Id.
-         * @param {int} pageSize Page size.
-         * @returns {Promise}
-         */
-        queryFetch(demo, queryId, pageSize) {
-            const cmd = new Command(demo, 'qryfetch')
-                .addParam('qryId', queryId)
-                .addParam('pageSize', pageSize);
-
-            return this.executeRest(cmd);
-        }
-
-        /**
-         * @param {Boolean} demo Is need run command on demo node.
-         * @param {int} queryId Query Id.
-         * @returns {Promise}
-         */
-        queryClose(demo, queryId) {
-            const cmd = new Command(demo, 'qrycls')
-                .addParam('qryId', queryId);
-
-            return this.executeRest(cmd);
-        }
-
-        /**
-         * @param {Boolean} demo Is need run command on demo node.
-         * @param {String} cacheName Cache name.
-         * @returns {Promise}
-         */
-        metadata(demo, cacheName) {
-            const cmd = new Command(demo, 'metadata')
-                .addParam('cacheName', cacheName);
-
-            return this.executeRest(cmd);
-        }
-
-        /**
-         * @param {Boolean} demo Is need run command on demo node.
-         * @param {String} evtOrderKey Event order key, unique for tab instance.
-         * @param {String} evtThrottleCntrKey Event throttle counter key, unique for tab instance.
-         * @returns {Promise}
-         */
-        collect(demo, evtOrderKey, evtThrottleCntrKey) {
-            const cmd = new Command(demo, 'exe')
-                .addParam('name', 'org.apache.ignite.internal.visor.compute.VisorGatewayTask')
-                .addParam('p1', '')
-                .addParam('p2', 'org.apache.ignite.internal.visor.node.VisorNodeDataCollectorTask')
-                .addParam('p3', 'org.apache.ignite.internal.visor.node.VisorNodeDataCollectorTaskArg')
-                .addParam('p4', true)
-                .addParam('p5', 'CONSOLE_' + evtOrderKey)
-                .addParam('p6', evtThrottleCntrKey)
-                .addParam('p7', 10)
-                .addParam('p8', false);
-
-            return this.executeRest(cmd);
-        }
-
-        /**
-         * @param {Boolean} demo Is need run command on demo node.
-         * @param {String} nid Node id.
-         * @param {String} cacheName Cache name.
-         * @returns {Promise}
-         */
-        cacheClear(demo, nid, cacheName) {
-            const cmd = new Command(demo, 'exe')
-                .addParam('name', 'org.apache.ignite.internal.visor.compute.VisorGatewayTask')
-                .addParam('p1', nid)
-                .addParam('p2', 'org.apache.ignite.internal.visor.cache.VisorCacheClearTask')
-                .addParam('p3', 'java.lang.String')
-                .addParam('p4', cacheName);
-
-            return this.executeRest(cmd);
-        }
-
-        /**
-         * @param {Boolean} demo Is need run command on demo node.
-         * @param {Array.<String>} nids Node ids.
-         * @param {Boolean} near true if near cache should be started.
-         * @param {String} cacheName Name for near cache.
-         * @param {String} cfg Cache XML configuration.
-         * @returns {Promise}
-         */
-        cacheStart(demo, nids, near, cacheName, cfg) {
-            const cmd = new Command(demo, 'exe')
-                .addParam('name', 'org.apache.ignite.internal.visor.compute.VisorGatewayTask')
-                .addParam('p1', nids)
-                .addParam('p2', 'org.apache.ignite.internal.visor.cache.VisorCacheStartTask')
-                .addParam('p3', 'org.apache.ignite.internal.visor.cache.VisorCacheStartTask$VisorCacheStartArg')
-                .addParam('p4', near)
-                .addParam('p5', cacheName)
-                .addParam('p6', cfg);
-
-            return this.executeRest(cmd);
-        }
-
-        /**
-         * @param {Boolean} demo Is need run command on demo node.
-         * @param {String} nid Node id.
-         * @param {String} cacheName Cache name.
-         * @returns {Promise}
-         */
-        cacheStop(demo, nid, cacheName) {
-            const cmd = new Command(demo, 'exe')
-                .addParam('name', 'org.apache.ignite.internal.visor.compute.VisorGatewayTask')
-                .addParam('p1', nid)
-                .addParam('p2', 'org.apache.ignite.internal.visor.cache.VisorCacheStopTask')
-                .addParam('p3', 'java.lang.String')
-                .addParam('p4', cacheName);
-
-            return this.executeRest(cmd);
-        }
-
-        /**
-         * @param {Boolean} demo Is need run command on demo node.
-         * @param {String} nid Node id.
-         * @param {String} cacheName Cache name.
-         * @returns {Promise}
-         */
-        cacheResetMetrics(demo, nid, cacheName) {
-            const cmd = new Command(demo, 'exe')
-                .addParam('name', 'org.apache.ignite.internal.visor.compute.VisorGatewayTask')
-                .addParam('p1', nid)
-                .addParam('p2', 'org.apache.ignite.internal.visor.cache.VisorCacheResetMetricsTask')
-                .addParam('p3', 'java.lang.String')
-                .addParam('p4', cacheName);
-
-            return this.executeRest(cmd);
-        }
-
-        /**
-         * @param {Boolean} demo Is need run command on demo node.
-         * @param {String} nid Node id.
-         * @param {String} cacheNames Cache names separated by comma.
-         * @returns {Promise}
-         */
-        cacheSwapBackups(demo, nid, cacheNames) {
-            const cmd = new Command(demo, 'exe')
-                .addParam('name', 'org.apache.ignite.internal.visor.compute.VisorGatewayTask')
-                .addParam('p1', nid)
-                .addParam('p2', 'org.apache.ignite.internal.visor.cache.VisorCacheSwapBackupsTask')
-                .addParam('p3', 'java.util.Set')
-                .addParam('p4', 'java.lang.String')
-                .addParam('p5', cacheNames);
-
-            return this.executeRest(cmd);
-        }
-
-        /**
-         * @param {Boolean} demo Is need run command on demo node.
-         * @param {String} nids Node ids.
-         * @returns {Promise}
-         */
-        gc(demo, nids) {
-            const cmd = new Command(demo, 'exe')
-                .addParam('name', 'org.apache.ignite.internal.visor.compute.VisorGatewayTask')
-                .addParam('p1', nids)
-                .addParam('p2', 'org.apache.ignite.internal.visor.node.VisorNodeGcTask')
-                .addParam('p3', 'java.lang.Void');
-
-            return this.executeRest(cmd);
-        }
-
-        /**
-         * @param {Boolean} demo Is need run command on demo node.
-         * @param {String} taskNid node that is not node we want to ping.
-         * @param {String} nid Id of the node to ping.
-         * @returns {Promise}
-         */
-        ping(demo, taskNid, nid) {
-            const cmd = new Command(demo, 'exe')
-                .addParam('name', 'org.apache.ignite.internal.visor.compute.VisorGatewayTask')
-                .addParam('p1', taskNid)
-                .addParam('p2', 'org.apache.ignite.internal.visor.node.VisorNodePingTask')
-                .addParam('p3', 'java.util.UUID')
-                .addParam('p4', nid);
-
-            return this.executeRest(cmd);
-        }
-
-        /**
-         * @param {Boolean} demo Is need run command on demo node.
-         * @param {String} nid Id of the node to get thread dump.
-         * @returns {Promise}
-         */
-        threadDump(demo, nid) {
-            const cmd = new Command(demo, 'exe')
-                .addParam('name', 'org.apache.ignite.internal.visor.compute.VisorGatewayTask')
-                .addParam('p1', nid)
-                .addParam('p2', 'org.apache.ignite.internal.visor.debug.VisorThreadDumpTask')
-                .addParam('p3', 'java.lang.Void');
-
-            return this.executeRest(cmd);
-        }
-    }
-
-    /**
-     * Connected agents manager.
-     */
-    class AgentManager {
-        /**
-         * @constructor
-         */
-        constructor() {
-            /**
-             * Connected agents by user id.
-             * @type {Object.<ObjectId, Array.<Agent>>}
-             */
-            this._agents = {};
-
-            /**
-             * Connected browsers by user id.
-             * @type {Object.<ObjectId, Array.<Socket>>}
-             */
-            this._browsers = {};
-
-            const agentArchives = fs.readdirSync(settings.agent.dists)
-                .filter((file) => path.extname(file) === '.zip');
-
-            /**
-             * Supported agents distribution.
-             * @type {Object.<String, String>}
-             */
-            this.supportedAgents = {};
-
-            const jarFilter = (file) => path.extname(file) === '.jar';
-
-            const agentsPromises = _.map(agentArchives, (fileName) => {
-                const filePath = path.join(settings.agent.dists, fileName);
-
-                return JSZip.loadAsync(fs.readFileSync(filePath))
-                    .then((zip) => {
-                        const jarPath = _.find(_.keys(zip.files), jarFilter);
-
-                        return JSZip.loadAsync(zip.files[jarPath].async('nodebuffer'))
-                            .then((jar) => jar.files['META-INF/MANIFEST.MF'].async('string'))
-                            .then((lines) => lines.trim()
-                                .split(/\s*\n+\s*/)
-                                .map((line, r) => {
-                                    r = line.split(/\s*:\s*/);
-
-                                    this[r[0]] = r[1];
-
-                                    return this;
-                                }, {})[0])
-                            .then((manifest) => {
-                                const ver = manifest['Implementation-Version'];
-                                const buildTime = manifest['Build-Time'];
-
-                                if (ver && buildTime)
-                                    return { fileName, filePath, ver, buildTime };
-                            });
-                    });
-            });
-
-            Promise.all(agentsPromises)
-                .then((agents) => {
-                    this.supportedAgents = _.keyBy(_.remove(agents, null), 'ver');
-
-                    const latest = _.head(Object.keys(this.supportedAgents).sort((a, b) => {
-                        const aParts = a.split('.');
-                        const bParts = b.split('.');
-
-                        for (let i = 0; i < aParts.length; ++i) {
-                            if (bParts.length === i)
-                                return 1;
-
-                            if (aParts[i] === aParts[i])
-                                continue;
-
-                            return aParts[i] > bParts[i] ? 1 : -1;
-                        }
-                    }));
-
-                    // Latest version of agent distribution.
-                    if (latest)
-                        this.supportedAgents.latest = this.supportedAgents[latest];
-                });
-        }
-
-        attachLegacy(server) {
-            const wsSrv = new ws.Server({server});
-
-            wsSrv.on('connection', (_wsClient) => {
-                _wsClient.send(JSON.stringify({
-                    method: 'authResult',
-                    args: ['You are using an older version of the agent. Please reload agent archive']
-                }));
-            });
-        }
-
-        /**
-         * @param {http.Server|https.Server} srv Server instance that we want to attach agent handler.
-         */
-        attach(srv) {
-            if (this._server)
-                throw 'Agent server already started!';
-
-            this._server = srv;
-
-            /**
-             * @type {socketIo.Server}
-             */
-            this._socket = socketio(this._server);
-
-            this._socket.on('connection', (socket) => {
-                socket.on('agent:auth', (data, cb) => {
-                    if (!_.isEmpty(this.supportedAgents)) {
-                        const ver = data.ver;
-                        const bt = data.bt;
-
-                        if (_.isEmpty(ver) || _.isEmpty(bt) || _.isEmpty(this.supportedAgents[ver]) ||
-                            this.supportedAgents[ver].buildTime > bt)
-                            return cb('You are using an older version of the agent. Please reload agent archive');
-                    }
-
-                    const tokens = data.tokens;
-
-                    mongo.Account.find({token: {$in: tokens}}, '_id token').lean().exec()
-                        .then((accounts) => {
-                            if (!accounts.length)
-                                return cb('Agent is failed to authenticate. Please check agent\'s token(s)');
-
-                            const agent = new Agent(socket);
-
-                            const accountIds = _.map(accounts, (account) => account._id);
-
-                            socket.on('disconnect', () => this._agentDisconnected(accountIds, agent));
-
-                            this._agentConnected(accountIds, agent);
-
-                            const missedTokens = _.difference(tokens, _.map(accounts, (account) => account.token));
-
-                            if (missedTokens.length) {
-                                agent._emit('agent:warning',
-                                    `Failed to authenticate with token(s): ${missedTokens.join(', ')}.`);
-                            }
-
-                            cb();
-                        })
-                        // TODO IGNITE-1379 send error to web master.
-                        .catch((err) => cb('Agent is failed to authenticate. Please check agent\'s tokens'));
-                });
-            });
-        }
-
-        /**
-         * @param {ObjectId} accountId
-         * @param {Socket} socket
-         * @returns {int} Connected agent count.
-         */
-        addAgentListener(accountId, socket) {
-            let sockets = this._browsers[accountId];
-
-            if (!sockets)
-                this._browsers[accountId] = sockets = [];
-
-            sockets.push(socket);
-
-            const agents = this._agents[accountId];
-
-            return agents ? agents.length : 0;
-        }
-
-        /**
-         * @param {ObjectId} accountId.
-         * @param {Socket} socket.
-         * @returns {int} connected agent count.
-         */
-        removeAgentListener(accountId, socket) {
-            const sockets = this._browsers[accountId];
-
-            _.pull(sockets, socket);
-        }
-
-        /**
-         * @param {ObjectId} accountId
-         * @returns {Promise.<Agent>}
-         */
-        findAgent(accountId) {
-            if (!this._server)
-                return Promise.reject(new Error('Agent server not started yet!'));
-
-            const agents = this._agents[accountId];
-
-            if (!agents || agents.length === 0)
-                return Promise.reject(new Error('Failed to connect to agent'));
-
-            return Promise.resolve(agents[0]);
-        }
-
-        /**
-         * Close connections for all user agents.
-         * @param {ObjectId} accountId
-         * @param {String} oldToken
-         */
-        close(accountId, oldToken) {
-            if (!this._server)
-                return;
-
-            const agentsForClose = this._agents[accountId];
-
-            const agentsForWarning = _.clone(agentsForClose);
-
-            this._agents[accountId] = [];
-
-            _.forEach(this._agents, (sockets) => _.pullAll(agentsForClose, sockets));
-
-            _.pullAll(agentsForWarning, agentsForClose);
-
-            const msg = `Security token has been reset: ${oldToken}`;
-
-            _.forEach(agentsForWarning, (socket) => socket._emit('agent:warning', msg));
-
-            _.forEach(agentsForClose, (socket) => socket._emit('agent:close', msg));
-
-            _.forEach(this._browsers[accountId], (socket) => socket.emit('agent:count', {count: 0}));
-        }
-
-        /**
-         * @param {ObjectId} accountIds
-         * @param {Agent} agent
-         */
-        _agentConnected(accountIds, agent) {
-            _.forEach(accountIds, (accountId) => {
-                let agents = this._agents[accountId];
-
-                if (!agents)
-                    this._agents[accountId] = agents = [];
-
-                agents.push(agent);
-
-                const sockets = this._browsers[accountId];
-
-                _.forEach(sockets, (socket) => socket.emit('agent:count', {count: agents.length}));
-            });
-        }
-
-        /**
-         * @param {ObjectId} accountIds
-         * @param {Agent} agent
-         */
-        _agentDisconnected(accountIds, agent) {
-            _.forEach(accountIds, (accountId) => {
-                const agents = this._agents[accountId];
-
-                if (agents && agents.length)
-                    _.pull(agents, agent);
-
-                const sockets = this._browsers[accountId];
-
-                _.forEach(sockets, (socket) => socket.emit('agent:count', {count: agents.length}));
-            });
-        }
-    }
-
-    return new AgentManager();
-};

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/src/main/js/serve/agent_dists/README.txt
----------------------------------------------------------------------
diff --git a/modules/web-console/src/main/js/serve/agent_dists/README.txt b/modules/web-console/src/main/js/serve/agent_dists/README.txt
deleted file mode 100644
index d51bdf9..0000000
--- a/modules/web-console/src/main/js/serve/agent_dists/README.txt
+++ /dev/null
@@ -1,7 +0,0 @@
-Ignite Web Console
-======================================
-
-This is default folder for agent distributives.
-
-Also, you could specify custom folder in `serve/config/settings.json`
-

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/src/main/js/serve/app.js
----------------------------------------------------------------------
diff --git a/modules/web-console/src/main/js/serve/app.js b/modules/web-console/src/main/js/serve/app.js
deleted file mode 100644
index 5d6b2cf..0000000
--- a/modules/web-console/src/main/js/serve/app.js
+++ /dev/null
@@ -1,42 +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.
- */
-
-'use strict';
-
-// Fire me up!
-
-module.exports = {
-    implements: 'app',
-    inject: ['require(express)', 'configure', 'routes']
-};
-
-module.exports.factory = function(Express, configure, routes) {
-    return {
-        /**
-         * @param {Server} srv
-         */
-        listen: (srv) => {
-            const app = new Express();
-
-            configure.express(app);
-
-            routes.register(app);
-
-            srv.addListener('request', app);
-        }
-    };
-};


[45/52] ignite git commit: Web Console beta-3.

Posted by ak...@apache.org.
http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-agent/src/main/java/org/apache/ignite/console/demo/AgentClusterDemo.java
----------------------------------------------------------------------
diff --git a/modules/web-agent/src/main/java/org/apache/ignite/console/demo/AgentClusterDemo.java b/modules/web-agent/src/main/java/org/apache/ignite/console/demo/AgentClusterDemo.java
deleted file mode 100644
index bf0903a..0000000
--- a/modules/web-agent/src/main/java/org/apache/ignite/console/demo/AgentClusterDemo.java
+++ /dev/null
@@ -1,638 +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.
- */
-
-package org.apache.ignite.console.demo;
-
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.Collection;
-import java.util.Collections;
-import java.util.HashSet;
-import java.util.LinkedHashMap;
-import java.util.Random;
-import java.util.Set;
-import java.util.concurrent.Executors;
-import java.util.concurrent.ScheduledExecutorService;
-import java.util.concurrent.ScheduledThreadPoolExecutor;
-import java.util.concurrent.ThreadFactory;
-import java.util.concurrent.TimeUnit;
-import java.util.concurrent.atomic.AtomicBoolean;
-import java.util.concurrent.atomic.AtomicInteger;
-import org.apache.ignite.Ignite;
-import org.apache.ignite.IgniteCache;
-import org.apache.ignite.Ignition;
-import org.apache.ignite.cache.CacheAtomicityMode;
-import org.apache.ignite.cache.QueryEntity;
-import org.apache.ignite.cache.QueryIndex;
-import org.apache.ignite.cache.QueryIndexType;
-import org.apache.ignite.cache.affinity.rendezvous.RendezvousAffinityFunction;
-import org.apache.ignite.configuration.CacheConfiguration;
-import org.apache.ignite.configuration.IgniteConfiguration;
-import org.apache.ignite.console.agent.AgentConfiguration;
-import org.apache.ignite.console.demo.model.Car;
-import org.apache.ignite.console.demo.model.Country;
-import org.apache.ignite.console.demo.model.Department;
-import org.apache.ignite.console.demo.model.Employee;
-import org.apache.ignite.console.demo.model.Parking;
-import org.apache.ignite.internal.IgniteEx;
-import org.apache.ignite.internal.util.typedef.F;
-import org.apache.ignite.logger.log4j.Log4JLogger;
-import org.apache.ignite.spi.communication.tcp.TcpCommunicationSpi;
-import org.apache.ignite.spi.discovery.tcp.TcpDiscoverySpi;
-import org.apache.ignite.spi.discovery.tcp.ipfinder.vm.TcpDiscoveryVmIpFinder;
-import org.apache.ignite.transactions.Transaction;
-import org.apache.log4j.Logger;
-
-import static org.apache.ignite.IgniteSystemProperties.IGNITE_ATOMIC_CACHE_DELETE_HISTORY_SIZE;
-import static org.apache.ignite.IgniteSystemProperties.IGNITE_PERFORMANCE_SUGGESTIONS_DISABLED;
-import static org.apache.ignite.IgniteSystemProperties.IGNITE_UPDATE_NOTIFIER;
-import static org.apache.ignite.IgniteSystemProperties.IGNITE_JETTY_PORT;
-import static org.apache.ignite.IgniteSystemProperties.IGNITE_NO_ASCII;
-import static org.apache.ignite.events.EventType.EVTS_DISCOVERY;
-import static org.apache.ignite.internal.IgniteNodeAttributes.ATTR_REST_JETTY_ADDRS;
-import static org.apache.ignite.internal.IgniteNodeAttributes.ATTR_REST_JETTY_PORT;
-import static org.apache.ignite.transactions.TransactionConcurrency.PESSIMISTIC;
-import static org.apache.ignite.transactions.TransactionIsolation.REPEATABLE_READ;
-
-/**
- * Demo for cluster features like SQL and Monitoring.
- *
- * Cache will be created and populated with data to query.
- */
-public class AgentClusterDemo {
-    /** */
-    private static final Logger log = Logger.getLogger(AgentClusterDemo.class.getName());
-
-    /** */
-    private static final AtomicBoolean initLatch = new AtomicBoolean();
-
-    /** */
-    private static final int NODE_CNT = 3;
-
-    /** */
-    private static final String COUNTRY_CACHE_NAME = "CountryCache";
-
-    /** */
-    private static final String DEPARTMENT_CACHE_NAME = "DepartmentCache";
-
-    /** */
-    private static final String EMPLOYEE_CACHE_NAME = "EmployeeCache";
-
-    /** */
-    private static final String PARKING_CACHE_NAME = "ParkingCache";
-
-    /** */
-    private static final String CAR_CACHE_NAME = "CarCache";
-
-    /** */
-    private static final Set<String> DEMO_CACHES = new HashSet<>(Arrays.asList(COUNTRY_CACHE_NAME,
-        DEPARTMENT_CACHE_NAME, EMPLOYEE_CACHE_NAME, PARKING_CACHE_NAME, CAR_CACHE_NAME));
-
-    /** */
-    private static final Random rnd = new Random();
-
-    /** Countries count. */
-    private static final int CNTR_CNT = 10;
-
-    /** Departments count */
-    private static final int DEP_CNT = 100;
-
-    /** Employees count. */
-    private static final int EMPL_CNT = 1000;
-
-    /** Countries count. */
-    private static final int CAR_CNT = 100;
-
-    /** Departments count */
-    private static final int PARK_CNT = 10;
-
-    /** Counter for threads in pool. */
-    private static final AtomicInteger THREAD_CNT = new AtomicInteger(0);
-
-    /**
-     * Create base cache configuration.
-     *
-     * @param name cache name.
-     * @return Cache configuration with basic properties set.
-     */
-    private static <K, V> CacheConfiguration<K, V> cacheConfiguration(String name) {
-        CacheConfiguration<K, V> ccfg = new CacheConfiguration<>(name);
-
-        ccfg.setAffinity(new RendezvousAffinityFunction(false, 32));
-        ccfg.setStartSize(100);
-        ccfg.setStatisticsEnabled(true);
-
-        return ccfg;
-    }
-
-    /**
-     * Configure cacheCountry.
-     */
-    private static <K, V> CacheConfiguration<K, V> cacheCountry() {
-        CacheConfiguration<K, V> ccfg = cacheConfiguration(COUNTRY_CACHE_NAME);
-
-        // Configure cacheCountry types.
-        Collection<QueryEntity> qryEntities = new ArrayList<>();
-
-        // COUNTRY.
-        QueryEntity type = new QueryEntity();
-
-        qryEntities.add(type);
-
-        type.setKeyType(Integer.class.getName());
-        type.setValueType(Country.class.getName());
-
-        // Query fields for COUNTRY.
-        LinkedHashMap<String, String> qryFlds = new LinkedHashMap<>();
-
-        qryFlds.put("id", "java.lang.Integer");
-        qryFlds.put("name", "java.lang.String");
-        qryFlds.put("population", "java.lang.Integer");
-
-        type.setFields(qryFlds);
-
-        ccfg.setQueryEntities(qryEntities);
-
-        return ccfg;
-    }
-
-    /**
-     * Configure cacheEmployee.
-     */
-    private static <K, V> CacheConfiguration<K, V> cacheDepartment() {
-        CacheConfiguration<K, V> ccfg = cacheConfiguration(DEPARTMENT_CACHE_NAME);
-
-        // Configure cacheDepartment types.
-        Collection<QueryEntity> qryEntities = new ArrayList<>();
-
-        // DEPARTMENT.
-        QueryEntity type = new QueryEntity();
-
-        qryEntities.add(type);
-
-        type.setKeyType(Integer.class.getName());
-        type.setValueType(Department.class.getName());
-
-        // Query fields for DEPARTMENT.
-        LinkedHashMap<String, String> qryFlds = new LinkedHashMap<>();
-
-        qryFlds.put("id", "java.lang.Integer");
-        qryFlds.put("countryId", "java.lang.Integer");
-        qryFlds.put("name", "java.lang.String");
-
-        type.setFields(qryFlds);
-
-        ccfg.setQueryEntities(qryEntities);
-
-        return ccfg;
-    }
-
-    /**
-     * Configure cacheEmployee.
-     */
-    private static <K, V> CacheConfiguration<K, V> cacheEmployee() {
-        CacheConfiguration<K, V> ccfg = cacheConfiguration(EMPLOYEE_CACHE_NAME);
-
-        ccfg.setAtomicityMode(CacheAtomicityMode.TRANSACTIONAL);
-        ccfg.setBackups(1);
-
-        // Configure cacheEmployee types.
-        Collection<QueryEntity> qryEntities = new ArrayList<>();
-
-        // EMPLOYEE.
-        QueryEntity type = new QueryEntity();
-
-        qryEntities.add(type);
-
-        type.setKeyType(Integer.class.getName());
-        type.setValueType(Employee.class.getName());
-
-        // Query fields for EMPLOYEE.
-        LinkedHashMap<String, String> qryFlds = new LinkedHashMap<>();
-
-        qryFlds.put("id", "java.lang.Integer");
-        qryFlds.put("departmentId", "java.lang.Integer");
-        qryFlds.put("managerId", "java.lang.Integer");
-        qryFlds.put("firstName", "java.lang.String");
-        qryFlds.put("lastName", "java.lang.String");
-        qryFlds.put("email", "java.lang.String");
-        qryFlds.put("phoneNumber", "java.lang.String");
-        qryFlds.put("hireDate", "java.sql.Date");
-        qryFlds.put("job", "java.lang.String");
-        qryFlds.put("salary", "java.lang.Double");
-
-        type.setFields(qryFlds);
-
-        // Indexes for EMPLOYEE.
-        Collection<QueryIndex> indexes = new ArrayList<>();
-
-        QueryIndex idx = new QueryIndex();
-
-        idx.setName("EMP_NAMES");
-        idx.setIndexType(QueryIndexType.SORTED);
-        LinkedHashMap<String, Boolean> indFlds = new LinkedHashMap<>();
-
-        indFlds.put("firstName", Boolean.FALSE);
-        indFlds.put("lastName", Boolean.FALSE);
-
-        idx.setFields(indFlds);
-
-        indexes.add(idx);
-        indexes.add(new QueryIndex("salary", QueryIndexType.SORTED, false, "EMP_SALARY"));
-
-        type.setIndexes(indexes);
-
-        ccfg.setQueryEntities(qryEntities);
-
-        return ccfg;
-    }
-
-    /**
-     * Configure cacheEmployee.
-     */
-    private static <K, V> CacheConfiguration<K, V> cacheParking() {
-        CacheConfiguration<K, V> ccfg = cacheConfiguration(PARKING_CACHE_NAME);
-
-        // Configure cacheParking types.
-        Collection<QueryEntity> qryEntities = new ArrayList<>();
-
-        // PARKING.
-        QueryEntity type = new QueryEntity();
-
-        qryEntities.add(type);
-
-        type.setKeyType(Integer.class.getName());
-        type.setValueType(Parking.class.getName());
-
-        // Query fields for PARKING.
-        LinkedHashMap<String, String> qryFlds = new LinkedHashMap<>();
-
-        qryFlds.put("id", "java.lang.Integer");
-        qryFlds.put("name", "java.lang.String");
-        qryFlds.put("capacity", "java.lang.Integer");
-
-        type.setFields(qryFlds);
-
-        ccfg.setQueryEntities(qryEntities);
-
-        return ccfg;
-    }
-
-    /**
-     * Configure cacheEmployee.
-     */
-    private static <K, V> CacheConfiguration<K, V> cacheCar() {
-        CacheConfiguration<K, V> ccfg = cacheConfiguration(CAR_CACHE_NAME);
-
-        // Configure cacheCar types.
-        Collection<QueryEntity> qryEntities = new ArrayList<>();
-
-        // CAR.
-        QueryEntity type = new QueryEntity();
-
-        qryEntities.add(type);
-
-        type.setKeyType(Integer.class.getName());
-        type.setValueType(Car.class.getName());
-
-        // Query fields for CAR.
-        LinkedHashMap<String, String> qryFlds = new LinkedHashMap<>();
-
-        qryFlds.put("id", "java.lang.Integer");
-        qryFlds.put("parkingId", "java.lang.Integer");
-        qryFlds.put("name", "java.lang.String");
-
-        type.setFields(qryFlds);
-
-        ccfg.setQueryEntities(qryEntities);
-
-        return ccfg;
-    }
-
-    /**
-     * Configure node.
-     * @param gridIdx Grid name index.
-     * @param client If {@code true} then start client node.
-     * @return IgniteConfiguration
-     */
-    private static  IgniteConfiguration igniteConfiguration(int gridIdx, boolean client) {
-        IgniteConfiguration cfg = new IgniteConfiguration();
-
-        cfg.setGridName((client ? "demo-server-" : "demo-client-") + gridIdx);
-        cfg.setLocalHost("127.0.0.1");
-        cfg.setIncludeEventTypes(EVTS_DISCOVERY);
-
-        TcpDiscoveryVmIpFinder ipFinder = new TcpDiscoveryVmIpFinder();
-
-        ipFinder.setAddresses(Collections.singletonList("127.0.0.1:60900.." + (60900 + NODE_CNT - 1)));
-
-        // Configure discovery SPI.
-        TcpDiscoverySpi discoSpi = new TcpDiscoverySpi();
-
-        discoSpi.setLocalPort(60900);
-        discoSpi.setIpFinder(ipFinder);
-
-        cfg.setDiscoverySpi(discoSpi);
-
-        TcpCommunicationSpi commSpi = new TcpCommunicationSpi();
-
-        commSpi.setSharedMemoryPort(-1);
-        commSpi.setLocalPort(60800);
-
-        cfg.setCommunicationSpi(commSpi);
-        cfg.setGridLogger(new Log4JLogger(log));
-        cfg.setMetricsLogFrequency(0);
-        cfg.getConnectorConfiguration().setPort(60700);
-
-        if (client)
-            cfg.setClientMode(true);
-
-        cfg.setCacheConfiguration(cacheCountry(), cacheDepartment(), cacheEmployee(), cacheParking(), cacheCar());
-
-        return cfg;
-    }
-
-    /**
-     * @param val Value to round.
-     * @param places Numbers after point.
-     * @return Rounded value;
-     */
-    private static double round(double val, int places) {
-        if (places < 0)
-            throw new IllegalArgumentException();
-
-        long factor = (long)Math.pow(10, places);
-
-        val *= factor;
-
-        long tmp = Math.round(val);
-
-        return (double)tmp / factor;
-    }
-
-    /**
-     * @param ignite Ignite.
-     * @param range Time range in milliseconds.
-     */
-    private static void populateCacheEmployee(Ignite ignite, long range) {
-        if (log.isDebugEnabled())
-            log.debug("DEMO: Start employees population with data...");
-
-        IgniteCache<Integer, Country> cacheCountry = ignite.cache(COUNTRY_CACHE_NAME);
-
-        for (int i = 0, n = 1; i < CNTR_CNT; i++, n++)
-            cacheCountry.put(i, new Country(i, "Country #" + n, n * 10000000));
-
-        IgniteCache<Integer, Department> cacheDepartment = ignite.cache(DEPARTMENT_CACHE_NAME);
-
-        IgniteCache<Integer, Employee> cacheEmployee = ignite.cache(EMPLOYEE_CACHE_NAME);
-
-        for (int i = 0, n = 1; i < DEP_CNT; i++, n++) {
-            cacheDepartment.put(i, new Department(n, rnd.nextInt(CNTR_CNT), "Department #" + n));
-
-            double r = rnd.nextDouble();
-
-            cacheEmployee.put(i, new Employee(i, rnd.nextInt(DEP_CNT), null, "First name manager #" + n,
-                "Last name manager #" + n, "Email manager #" + n, "Phone number manager #" + n,
-                new java.sql.Date((long)(r * range)), "Job manager #" + n, 1000 + round(r * 4000, 2)));
-        }
-
-        for (int i = 0, n = 1; i < EMPL_CNT; i++, n++) {
-            Integer depId = rnd.nextInt(DEP_CNT);
-
-            double r = rnd.nextDouble();
-
-            cacheEmployee.put(i, new Employee(i, depId, depId, "First name employee #" + n,
-                "Last name employee #" + n, "Email employee #" + n, "Phone number employee #" + n,
-                new java.sql.Date((long)(r * range)), "Job employee #" + n, 500 + round(r * 2000, 2)));
-        }
-
-        if (log.isDebugEnabled())
-            log.debug("DEMO: Finished employees population.");
-    }
-
-    /**
-     * @param ignite Ignite.
-     */
-    private static void populateCacheCar(Ignite ignite) {
-        if (log.isDebugEnabled())
-            log.debug("DEMO: Start cars population...");
-
-        IgniteCache<Integer, Parking> cacheParking = ignite.cache(PARKING_CACHE_NAME);
-
-        for (int i = 0, n = 1; i < PARK_CNT; i++, n++)
-            cacheParking.put(i, new Parking(i, "Parking #" + n, n * 10));
-
-        IgniteCache<Integer, Car> cacheCar = ignite.cache(CAR_CACHE_NAME);
-
-        for (int i = 0, n = 1; i < CAR_CNT; i++, n++)
-            cacheCar.put(i, new Car(i, rnd.nextInt(PARK_CNT), "Car #" + n));
-
-        if (log.isDebugEnabled())
-            log.debug("DEMO: Finished cars population.");
-    }
-
-    /**
-     * Creates a thread pool that can schedule commands to run after a given delay, or to execute periodically.
-     *
-     * @param corePoolSize Number of threads to keep in the pool, even if they are idle.
-     * @param threadName Part of thread name that would be used by thread factory.
-     * @return Newly created scheduled thread pool.
-     */
-    private static ScheduledExecutorService newScheduledThreadPool(int corePoolSize, final String threadName) {
-        ScheduledExecutorService srvc = Executors.newScheduledThreadPool(corePoolSize, new ThreadFactory() {
-            @Override public Thread newThread(Runnable r) {
-                Thread thread = new Thread(r, String.format("%s-%d", threadName, THREAD_CNT.getAndIncrement()));
-
-                thread.setDaemon(true);
-
-                return thread;
-            }
-        });
-
-        ScheduledThreadPoolExecutor executor = (ScheduledThreadPoolExecutor)srvc;
-
-        // Setting up shutdown policy.
-        executor.setExecuteExistingDelayedTasksAfterShutdownPolicy(false);
-        executor.setContinueExistingPeriodicTasksAfterShutdownPolicy(false);
-
-        return srvc;
-    }
-
-    /**
-     * Starts read and write from cache in background.
-     *
-     * @param ignite Ignite.
-     * @param cnt - maximum count read/write key
-     */
-    private static void startLoad(final Ignite ignite, final int cnt) {
-        final long diff = new java.util.Date().getTime();
-
-        populateCacheEmployee(ignite, diff);
-        populateCacheCar(ignite);
-
-        ScheduledExecutorService cachePool = newScheduledThreadPool(2, "demo-sql-load-cache-tasks");
-
-        cachePool.scheduleWithFixedDelay(new Runnable() {
-            @Override public void run() {
-                try {
-                    for (String cacheName : ignite.cacheNames()) {
-                        if (!DEMO_CACHES.contains(cacheName)) {
-                            IgniteCache<Integer, String> otherCache = ignite.cache(cacheName);
-
-                            if (otherCache != null) {
-                                for (int i = 0, n = 1; i < cnt; i++, n++) {
-                                    Integer key = rnd.nextInt(1000);
-
-                                    String val = otherCache.get(key);
-
-                                    if (val == null)
-                                        otherCache.put(key, "other-" + key);
-                                    else if (rnd.nextInt(100) < 30)
-                                        otherCache.remove(key);
-                                }
-                            }
-                        }
-                    }
-
-                    IgniteCache<Integer, Employee> cacheEmployee = ignite.cache(EMPLOYEE_CACHE_NAME);
-
-                    if (cacheEmployee != null)
-                        try(Transaction tx = ignite.transactions().txStart(PESSIMISTIC, REPEATABLE_READ)) {
-                            for (int i = 0, n = 1; i < cnt; i++, n++) {
-                                Integer id = rnd.nextInt(EMPL_CNT);
-
-                                Integer depId = rnd.nextInt(DEP_CNT);
-
-                                double r = rnd.nextDouble();
-
-                                cacheEmployee.put(id, new Employee(id, depId, depId, "First name employee #" + n,
-                                    "Last name employee #" + n, "Email employee #" + n, "Phone number employee #" + n,
-                                    new java.sql.Date((long)(r * diff)), "Job employee #" + n, 500 + round(r * 2000, 2)));
-
-                                if (rnd.nextBoolean())
-                                    cacheEmployee.remove(rnd.nextInt(EMPL_CNT));
-
-                                cacheEmployee.get(rnd.nextInt(EMPL_CNT));
-                            }
-
-                            if (rnd.nextInt(100) > 20)
-                                tx.commit();
-                        }
-                }
-                catch (Throwable e) {
-                    if (!e.getMessage().contains("cache is stopped"))
-                        ignite.log().error("Cache write task execution error", e);
-                }
-            }
-        }, 10, 3, TimeUnit.SECONDS);
-
-        cachePool.scheduleWithFixedDelay(new Runnable() {
-            @Override public void run() {
-                try {
-                    IgniteCache<Integer, Car> cache = ignite.cache(CAR_CACHE_NAME);
-
-                    if (cache != null)
-                        for (int i = 0; i < cnt; i++) {
-                            Integer carId = rnd.nextInt(CAR_CNT);
-
-                            cache.put(carId, new Car(carId, rnd.nextInt(PARK_CNT), "Car #" + (i + 1)));
-
-                            if (rnd.nextBoolean())
-                                cache.remove(rnd.nextInt(CAR_CNT));
-                        }
-                }
-                catch (IllegalStateException ignored) {
-                    // No-op.
-                }
-                catch (Throwable e) {
-                    if (!e.getMessage().contains("cache is stopped"))
-                        ignite.log().error("Cache write task execution error", e);
-                }
-            }
-        }, 10, 3, TimeUnit.SECONDS);
-    }
-
-    /**
-     * Start ignite node with cacheEmployee and populate it with data.
-     */
-    public static boolean testDrive(AgentConfiguration acfg) {
-        if (initLatch.compareAndSet(false, true)) {
-            log.info("DEMO: Starting embedded nodes for demo...");
-
-            System.setProperty(IGNITE_ATOMIC_CACHE_DELETE_HISTORY_SIZE, "1");
-            System.setProperty(IGNITE_PERFORMANCE_SUGGESTIONS_DISABLED, "true");
-            System.setProperty(IGNITE_UPDATE_NOTIFIER, "false");
-
-            System.setProperty(IGNITE_JETTY_PORT, "60800");
-            System.setProperty(IGNITE_NO_ASCII, "true");
-
-            try {
-                IgniteEx ignite = (IgniteEx)Ignition.start(igniteConfiguration(0, false));
-
-                final AtomicInteger cnt = new AtomicInteger(0);
-
-                final ScheduledExecutorService execSrv = Executors.newSingleThreadScheduledExecutor();
-
-                execSrv.scheduleAtFixedRate(new Runnable() {
-                    @Override public void run() {
-                        int idx = cnt.incrementAndGet();
-
-                        try {
-                            Ignition.start(igniteConfiguration(idx, idx == NODE_CNT));
-                        }
-                        catch (Throwable e) {
-                            log.error("DEMO: Failed to start embedded node: " + e.getMessage());
-                        }
-                        finally {
-                            if (idx == NODE_CNT)
-                                execSrv.shutdown();
-                        }
-                    }
-                }, 10, 10, TimeUnit.SECONDS);
-
-                if (log.isDebugEnabled())
-                    log.debug("DEMO: Started embedded nodes with indexed enabled caches...");
-
-                Collection<String> jettyAddrs = ignite.localNode().attribute(ATTR_REST_JETTY_ADDRS);
-
-                String host = jettyAddrs == null ? null : jettyAddrs.iterator().next();
-
-                Integer port = ignite.localNode().attribute(ATTR_REST_JETTY_PORT);
-
-                if (F.isEmpty(host) || port == null) {
-                    log.error("DEMO: Failed to start embedded node with rest!");
-
-                    return false;
-                }
-
-                acfg.demoNodeUri(String.format("http://%s:%d", host, port));
-
-                log.info("DEMO: Embedded nodes for sql and monitoring demo successfully started");
-
-                startLoad(ignite, 20);
-            }
-            catch (Exception e) {
-                log.error("DEMO: Failed to start embedded node for sql and monitoring demo!", e);
-
-                return false;
-            }
-        }
-
-        return true;
-    }
-}

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-agent/src/main/java/org/apache/ignite/console/demo/AgentMetadataDemo.java
----------------------------------------------------------------------
diff --git a/modules/web-agent/src/main/java/org/apache/ignite/console/demo/AgentMetadataDemo.java b/modules/web-agent/src/main/java/org/apache/ignite/console/demo/AgentMetadataDemo.java
deleted file mode 100644
index 4683dd8..0000000
--- a/modules/web-agent/src/main/java/org/apache/ignite/console/demo/AgentMetadataDemo.java
+++ /dev/null
@@ -1,92 +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.
- */
-
-package org.apache.ignite.console.demo;
-
-import java.io.File;
-import java.io.FileNotFoundException;
-import java.io.FileReader;
-import java.sql.Connection;
-import java.sql.DriverManager;
-import java.sql.SQLException;
-import java.util.concurrent.atomic.AtomicBoolean;
-import org.apache.log4j.Logger;
-import org.h2.tools.RunScript;
-import org.h2.tools.Server;
-
-import static org.apache.ignite.console.agent.AgentUtils.resolvePath;
-
-/**
- * Demo for metadata load from database.
- *
- * H2 database will be started and several tables will be created.
- */
-public class AgentMetadataDemo {
-    /** */
-    private static final Logger log = Logger.getLogger(AgentMetadataDemo.class.getName());
-
-    /** */
-    private static final AtomicBoolean initLatch = new AtomicBoolean();
-
-    /**
-     * @param jdbcUrl Connection url.
-     * @return true if url is used for test-drive.
-     */
-    public static boolean isTestDriveUrl(String jdbcUrl) {
-        return "jdbc:h2:mem:demo-db".equals(jdbcUrl);
-    }
-
-    /**
-     * Start H2 database and populate it with several tables.
-     */
-    public static Connection testDrive() throws SQLException {
-        if (initLatch.compareAndSet(false, true)) {
-            log.info("DEMO: Prepare in-memory H2 database...");
-
-            try {
-                Connection conn = DriverManager.getConnection("jdbc:h2:mem:demo-db;DB_CLOSE_DELAY=-1", "sa", "");
-
-                File sqlScript = resolvePath("demo/db-init.sql");
-
-                //noinspection ConstantConditions
-                RunScript.execute(conn, new FileReader(sqlScript));
-
-                log.info("DEMO: Sample tables created.");
-
-                conn.close();
-
-                Server.createTcpServer("-tcpDaemon").start();
-
-                log.info("DEMO: TcpServer stared.");
-
-                log.info("DEMO: JDBC URL for test drive metadata load: jdbc:h2:mem:demo-db");
-            }
-            catch (SQLException e) {
-                log.error("DEMO: Failed to start test drive for metadata!", e);
-
-                throw e;
-            }
-            catch (FileNotFoundException | NullPointerException e) {
-                log.error("DEMO: Failed to find demo database init script file: demo/db-init.sql");
-
-                throw new SQLException("Failed to start demo for metadata", e);
-            }
-        }
-
-        return DriverManager.getConnection("jdbc:h2:mem:demo-db;DB_CLOSE_DELAY=-1", "sa", "");
-    }
-}

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-agent/src/main/java/org/apache/ignite/console/demo/model/Car.java
----------------------------------------------------------------------
diff --git a/modules/web-agent/src/main/java/org/apache/ignite/console/demo/model/Car.java b/modules/web-agent/src/main/java/org/apache/ignite/console/demo/model/Car.java
deleted file mode 100644
index f351efc..0000000
--- a/modules/web-agent/src/main/java/org/apache/ignite/console/demo/model/Car.java
+++ /dev/null
@@ -1,152 +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.
- */
-
-package org.apache.ignite.console.demo.model;
-
-import java.io.Serializable;
-
-/**
- * Car definition.
- */
-public class Car implements Serializable {
-    /** */
-    private static final long serialVersionUID = 0L;
-
-    /** Value for id. */
-    private int id;
-
-    /** Value for parkingId. */
-    private int parkingId;
-
-    /** Value for name. */
-    private String name;
-
-    /**
-     * Empty constructor.
-     */
-    public Car() {
-        // No-op.
-    }
-
-    /**
-     * Full constructor.
-     */
-    public Car(
-        int id,
-        int parkingId,
-        String name
-    ) {
-        this.id = id;
-        this.parkingId = parkingId;
-        this.name = name;
-    }
-
-    /**
-     * Gets id.
-     *
-     * @return Value for id.
-     */
-    public int getId() {
-        return id;
-    }
-
-    /**
-     * Sets id.
-     *
-     * @param id New value for id.
-     */
-    public void setId(int id) {
-        this.id = id;
-    }
-
-    /**
-     * Gets parkingId.
-     *
-     * @return Value for parkingId.
-     */
-    public int getParkingId() {
-        return parkingId;
-    }
-
-    /**
-     * Sets parkingId.
-     *
-     * @param parkingId New value for parkingId.
-     */
-    public void setParkingId(int parkingId) {
-        this.parkingId = parkingId;
-    }
-
-    /**
-     * Gets name.
-     *
-     * @return Value for name.
-     */
-    public String getName() {
-        return name;
-    }
-
-    /**
-     * Sets name.
-     *
-     * @param name New value for name.
-     */
-    public void setName(String name) {
-        this.name = name;
-    }
-
-    /** {@inheritDoc} */
-    @Override public boolean equals(Object o) {
-        if (this == o)
-            return true;
-        
-        if (!(o instanceof Car))
-            return false;
-
-        Car that = (Car)o;
-
-        if (id != that.id)
-            return false;
-
-        if (parkingId != that.parkingId)
-            return false;
-
-        if (name != null ? !name.equals(that.name) : that.name != null)
-            return false;
-
-        return true;
-    }
-
-    /** {@inheritDoc} */
-    @Override public int hashCode() {
-        int res = id;
-
-        res = 31 * res + parkingId;
-
-        res = 31 * res + (name != null ? name.hashCode() : 0);
-
-        return res;
-    }
-
-    /** {@inheritDoc} */
-    @Override public String toString() {
-        return "Car [id=" + id +
-            ", parkingId=" + parkingId +
-            ", name=" + name +
-            ']';
-    }
-}

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-agent/src/main/java/org/apache/ignite/console/demo/model/Country.java
----------------------------------------------------------------------
diff --git a/modules/web-agent/src/main/java/org/apache/ignite/console/demo/model/Country.java b/modules/web-agent/src/main/java/org/apache/ignite/console/demo/model/Country.java
deleted file mode 100644
index 348928b..0000000
--- a/modules/web-agent/src/main/java/org/apache/ignite/console/demo/model/Country.java
+++ /dev/null
@@ -1,152 +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.
- */
-
-package org.apache.ignite.console.demo.model;
-
-import java.io.Serializable;
-
-/**
- * Country definition.
- */
-public class Country implements Serializable {
-    /** */
-    private static final long serialVersionUID = 0L;
-
-    /** Value for id. */
-    private int id;
-
-    /** Value for name. */
-    private String name;
-
-    /** Value for population. */
-    private int population;
-
-    /**
-     * Empty constructor.
-     */
-    public Country() {
-        // No-op.
-    }
-
-    /**
-     * Full constructor.
-     */
-    public Country(
-        int id,
-        String name,
-        int population
-    ) {
-        this.id = id;
-        this.name = name;
-        this.population = population;
-    }
-
-    /**
-     * Gets id.
-     *
-     * @return Value for id.
-     */
-    public int getId() {
-        return id;
-    }
-
-    /**
-     * Sets id.
-     *
-     * @param id New value for id.
-     */
-    public void setId(int id) {
-        this.id = id;
-    }
-
-    /**
-     * Gets name.
-     *
-     * @return Value for name.
-     */
-    public String getName() {
-        return name;
-    }
-
-    /**
-     * Sets name.
-     *
-     * @param name New value for name.
-     */
-    public void setName(String name) {
-        this.name = name;
-    }
-
-    /**
-     * Gets population.
-     *
-     * @return Value for population.
-     */
-    public int getPopulation() {
-        return population;
-    }
-
-    /**
-     * Sets population.
-     *
-     * @param population New value for population.
-     */
-    public void setPopulation(int population) {
-        this.population = population;
-    }
-
-    /** {@inheritDoc} */
-    @Override public boolean equals(Object o) {
-        if (this == o)
-            return true;
-        
-        if (!(o instanceof Country))
-            return false;
-
-        Country that = (Country)o;
-
-        if (id != that.id)
-            return false;
-
-        if (name != null ? !name.equals(that.name) : that.name != null)
-            return false;
-
-        if (population != that.population)
-            return false;
-
-        return true;
-    }
-
-    /** {@inheritDoc} */
-    @Override public int hashCode() {
-        int res = id;
-
-        res = 31 * res + (name != null ? name.hashCode() : 0);
-
-        res = 31 * res + population;
-
-        return res;
-    }
-
-    /** {@inheritDoc} */
-    @Override public String toString() {
-        return "Country [id=" + id +
-            ", name=" + name +
-            ", population=" + population +
-            ']';
-    }
-}

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-agent/src/main/java/org/apache/ignite/console/demo/model/Department.java
----------------------------------------------------------------------
diff --git a/modules/web-agent/src/main/java/org/apache/ignite/console/demo/model/Department.java b/modules/web-agent/src/main/java/org/apache/ignite/console/demo/model/Department.java
deleted file mode 100644
index 1c2f3b2..0000000
--- a/modules/web-agent/src/main/java/org/apache/ignite/console/demo/model/Department.java
+++ /dev/null
@@ -1,152 +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.
- */
-
-package org.apache.ignite.console.demo.model;
-
-import java.io.Serializable;
-
-/**
- * Department definition.
- */
-public class Department implements Serializable {
-    /** */
-    private static final long serialVersionUID = 0L;
-
-    /** Value for id. */
-    private int id;
-
-    /** Value for countryId. */
-    private int countryId;
-
-    /** Value for name. */
-    private String name;
-
-    /**
-     * Empty constructor.
-     */
-    public Department() {
-        // No-op.
-    }
-
-    /**
-     * Full constructor.
-     */
-    public Department(
-        int id,
-        int countryId,
-        String name
-    ) {
-        this.id = id;
-        this.countryId = countryId;
-        this.name = name;
-    }
-
-    /**
-     * Gets id.
-     *
-     * @return Value for id.
-     */
-    public int getId() {
-        return id;
-    }
-
-    /**
-     * Sets id.
-     *
-     * @param id New value for id.
-     */
-    public void setId(int id) {
-        this.id = id;
-    }
-
-    /**
-     * Gets countryId.
-     *
-     * @return Value for countryId.
-     */
-    public int getCountryId() {
-        return countryId;
-    }
-
-    /**
-     * Sets countryId.
-     *
-     * @param countryId New value for countryId.
-     */
-    public void setCountryId(int countryId) {
-        this.countryId = countryId;
-    }
-
-    /**
-     * Gets name.
-     *
-     * @return Value for name.
-     */
-    public String getName() {
-        return name;
-    }
-
-    /**
-     * Sets name.
-     *
-     * @param name New value for name.
-     */
-    public void setName(String name) {
-        this.name = name;
-    }
-
-    /** {@inheritDoc} */
-    @Override public boolean equals(Object o) {
-        if (this == o)
-            return true;
-        
-        if (!(o instanceof Department))
-            return false;
-
-        Department that = (Department)o;
-
-        if (id != that.id)
-            return false;
-
-        if (countryId != that.countryId)
-            return false;
-
-        if (name != null ? !name.equals(that.name) : that.name != null)
-            return false;
-
-        return true;
-    }
-
-    /** {@inheritDoc} */
-    @Override public int hashCode() {
-        int res = id;
-
-        res = 31 * res + countryId;
-
-        res = 31 * res + (name != null ? name.hashCode() : 0);
-
-        return res;
-    }
-
-    /** {@inheritDoc} */
-    @Override public String toString() {
-        return "Department [id=" + id +
-            ", countryId=" + countryId +
-            ", name=" + name +
-            ']';
-    }
-}

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-agent/src/main/java/org/apache/ignite/console/demo/model/Employee.java
----------------------------------------------------------------------
diff --git a/modules/web-agent/src/main/java/org/apache/ignite/console/demo/model/Employee.java b/modules/web-agent/src/main/java/org/apache/ignite/console/demo/model/Employee.java
deleted file mode 100644
index a3e7eba..0000000
--- a/modules/web-agent/src/main/java/org/apache/ignite/console/demo/model/Employee.java
+++ /dev/null
@@ -1,356 +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.
- */
-
-package org.apache.ignite.console.demo.model;
-
-import java.io.Serializable;
-import java.sql.Date;
-
-/**
- * Employee definition.
- */
-public class Employee implements Serializable {
-    /** */
-    private static final long serialVersionUID = 0L;
-
-    /** Value for id. */
-    private int id;
-
-    /** Value for departmentId. */
-    private int departmentId;
-
-    /** Value for managerId. */
-    private Integer managerId;
-
-    /** Value for firstName. */
-    private String firstName;
-
-    /** Value for lastName. */
-    private String lastName;
-
-    /** Value for email. */
-    private String email;
-
-    /** Value for phoneNumber. */
-    private String phoneNumber;
-
-    /** Value for hireDate. */
-    private Date hireDate;
-
-    /** Value for job. */
-    private String job;
-
-    /** Value for salary. */
-    private Double salary;
-
-    /**
-     * Empty constructor.
-     */
-    public Employee() {
-        // No-op.
-    }
-
-    /**
-     * Full constructor.
-     */
-    public Employee(
-        int id,
-        int departmentId,
-        Integer managerId,
-        String firstName,
-        String lastName,
-        String email,
-        String phoneNumber,
-        Date hireDate,
-        String job,
-        Double salary
-    ) {
-        this.id = id;
-        this.departmentId = departmentId;
-        this.managerId = managerId;
-        this.firstName = firstName;
-        this.lastName = lastName;
-        this.email = email;
-        this.phoneNumber = phoneNumber;
-        this.hireDate = hireDate;
-        this.job = job;
-        this.salary = salary;
-    }
-
-    /**
-     * Gets id.
-     *
-     * @return Value for id.
-     */
-    public int getId() {
-        return id;
-    }
-
-    /**
-     * Sets id.
-     *
-     * @param id New value for id.
-     */
-    public void setId(int id) {
-        this.id = id;
-    }
-
-    /**
-     * Gets departmentId.
-     *
-     * @return Value for departmentId.
-     */
-    public int getDepartmentId() {
-        return departmentId;
-    }
-
-    /**
-     * Sets departmentId.
-     *
-     * @param departmentId New value for departmentId.
-     */
-    public void setDepartmentId(int departmentId) {
-        this.departmentId = departmentId;
-    }
-
-    /**
-     * Gets managerId.
-     *
-     * @return Value for managerId.
-     */
-    public Integer getManagerId() {
-        return managerId;
-    }
-
-    /**
-     * Sets managerId.
-     *
-     * @param managerId New value for managerId.
-     */
-    public void setManagerId(Integer managerId) {
-        this.managerId = managerId;
-    }
-
-    /**
-     * Gets firstName.
-     *
-     * @return Value for firstName.
-     */
-    public String getFirstName() {
-        return firstName;
-    }
-
-    /**
-     * Sets firstName.
-     *
-     * @param firstName New value for firstName.
-     */
-    public void setFirstName(String firstName) {
-        this.firstName = firstName;
-    }
-
-    /**
-     * Gets lastName.
-     *
-     * @return Value for lastName.
-     */
-    public String getLastName() {
-        return lastName;
-    }
-
-    /**
-     * Sets lastName.
-     *
-     * @param lastName New value for lastName.
-     */
-    public void setLastName(String lastName) {
-        this.lastName = lastName;
-    }
-
-    /**
-     * Gets email.
-     *
-     * @return Value for email.
-     */
-    public String getEmail() {
-        return email;
-    }
-
-    /**
-     * Sets email.
-     *
-     * @param email New value for email.
-     */
-    public void setEmail(String email) {
-        this.email = email;
-    }
-
-    /**
-     * Gets phoneNumber.
-     *
-     * @return Value for phoneNumber.
-     */
-    public String getPhoneNumber() {
-        return phoneNumber;
-    }
-
-    /**
-     * Sets phoneNumber.
-     *
-     * @param phoneNumber New value for phoneNumber.
-     */
-    public void setPhoneNumber(String phoneNumber) {
-        this.phoneNumber = phoneNumber;
-    }
-
-    /**
-     * Gets hireDate.
-     *
-     * @return Value for hireDate.
-     */
-    public Date getHireDate() {
-        return hireDate;
-    }
-
-    /**
-     * Sets hireDate.
-     *
-     * @param hireDate New value for hireDate.
-     */
-    public void setHireDate(Date hireDate) {
-        this.hireDate = hireDate;
-    }
-
-    /**
-     * Gets job.
-     *
-     * @return Value for job.
-     */
-    public String getJob() {
-        return job;
-    }
-
-    /**
-     * Sets job.
-     *
-     * @param job New value for job.
-     */
-    public void setJob(String job) {
-        this.job = job;
-    }
-
-    /**
-     * Gets salary.
-     *
-     * @return Value for salary.
-     */
-    public Double getSalary() {
-        return salary;
-    }
-
-    /**
-     * Sets salary.
-     *
-     * @param salary New value for salary.
-     */
-    public void setSalary(Double salary) {
-        this.salary = salary;
-    }
-
-    /** {@inheritDoc} */
-    @Override public boolean equals(Object o) {
-        if (this == o)
-            return true;
-        
-        if (!(o instanceof Employee))
-            return false;
-
-        Employee that = (Employee)o;
-
-        if (id != that.id)
-            return false;
-
-        if (departmentId != that.departmentId)
-            return false;
-
-        if (managerId != null ? !managerId.equals(that.managerId) : that.managerId != null)
-            return false;
-
-        if (firstName != null ? !firstName.equals(that.firstName) : that.firstName != null)
-            return false;
-
-        if (lastName != null ? !lastName.equals(that.lastName) : that.lastName != null)
-            return false;
-
-        if (email != null ? !email.equals(that.email) : that.email != null)
-            return false;
-
-        if (phoneNumber != null ? !phoneNumber.equals(that.phoneNumber) : that.phoneNumber != null)
-            return false;
-
-        if (hireDate != null ? !hireDate.equals(that.hireDate) : that.hireDate != null)
-            return false;
-
-        if (job != null ? !job.equals(that.job) : that.job != null)
-            return false;
-
-        if (salary != null ? !salary.equals(that.salary) : that.salary != null)
-            return false;
-
-        return true;
-    }
-
-    /** {@inheritDoc} */
-    @Override public int hashCode() {
-        int res = id;
-
-        res = 31 * res + departmentId;
-
-        res = 31 * res + (managerId != null ? managerId.hashCode() : 0);
-
-        res = 31 * res + (firstName != null ? firstName.hashCode() : 0);
-
-        res = 31 * res + (lastName != null ? lastName.hashCode() : 0);
-
-        res = 31 * res + (email != null ? email.hashCode() : 0);
-
-        res = 31 * res + (phoneNumber != null ? phoneNumber.hashCode() : 0);
-
-        res = 31 * res + (hireDate != null ? hireDate.hashCode() : 0);
-
-        res = 31 * res + (job != null ? job.hashCode() : 0);
-
-        res = 31 * res + (salary != null ? salary.hashCode() : 0);
-
-        return res;
-    }
-
-    /** {@inheritDoc} */
-    @Override public String toString() {
-        return "Employee [id=" + id +
-            ", departmentId=" + departmentId +
-            ", managerId=" + managerId +
-            ", firstName=" + firstName +
-            ", lastName=" + lastName +
-            ", email=" + email +
-            ", phoneNumber=" + phoneNumber +
-            ", hireDate=" + hireDate +
-            ", job=" + job +
-            ", salary=" + salary +
-            ']';
-    }
-}

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-agent/src/main/java/org/apache/ignite/console/demo/model/Parking.java
----------------------------------------------------------------------
diff --git a/modules/web-agent/src/main/java/org/apache/ignite/console/demo/model/Parking.java b/modules/web-agent/src/main/java/org/apache/ignite/console/demo/model/Parking.java
deleted file mode 100644
index d55ae81..0000000
--- a/modules/web-agent/src/main/java/org/apache/ignite/console/demo/model/Parking.java
+++ /dev/null
@@ -1,152 +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.
- */
-
-package org.apache.ignite.console.demo.model;
-
-import java.io.Serializable;
-
-/**
- * Parking definition.
- */
-public class Parking implements Serializable {
-    /** */
-    private static final long serialVersionUID = 0L;
-
-    /** Value for id. */
-    private int id;
-
-    /** Value for name. */
-    private String name;
-
-    /** Value for capacity. */
-    private int capacity;
-
-    /**
-     * Empty constructor.
-     */
-    public Parking() {
-        // No-op.
-    }
-
-    /**
-     * Full constructor.
-     */
-    public Parking(
-        int id,
-        String name,
-        int capacity
-    ) {
-        this.id = id;
-        this.name = name;
-        this.capacity = capacity;
-    }
-
-    /**
-     * Gets id.
-     *
-     * @return Value for id.
-     */
-    public int getId() {
-        return id;
-    }
-
-    /**
-     * Sets id.
-     *
-     * @param id New value for id.
-     */
-    public void setId(int id) {
-        this.id = id;
-    }
-
-    /**
-     * Gets name.
-     *
-     * @return Value for name.
-     */
-    public String getName() {
-        return name;
-    }
-
-    /**
-     * Sets name.
-     *
-     * @param name New value for name.
-     */
-    public void setName(String name) {
-        this.name = name;
-    }
-
-    /**
-     * Gets capacity.
-     *
-     * @return Value for capacity.
-     */
-    public int getCapacity() {
-        return capacity;
-    }
-
-    /**
-     * Sets capacity.
-     *
-     * @param capacity New value for capacity.
-     */
-    public void setCapacity(int capacity) {
-        this.capacity = capacity;
-    }
-
-    /** {@inheritDoc} */
-    @Override public boolean equals(Object o) {
-        if (this == o)
-            return true;
-        
-        if (!(o instanceof Parking))
-            return false;
-
-        Parking that = (Parking)o;
-
-        if (id != that.id)
-            return false;
-
-        if (name != null ? !name.equals(that.name) : that.name != null)
-            return false;
-
-        if (capacity != that.capacity)
-            return false;
-
-        return true;
-    }
-
-    /** {@inheritDoc} */
-    @Override public int hashCode() {
-        int res = id;
-
-        res = 31 * res + (name != null ? name.hashCode() : 0);
-
-        res = 31 * res + capacity;
-
-        return res;
-    }
-
-    /** {@inheritDoc} */
-    @Override public String toString() {
-        return "Parking [id=" + id +
-            ", name=" + name +
-            ", capacity=" + capacity +
-            ']';
-    }
-}

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-agent/src/main/resources/log4j.properties
----------------------------------------------------------------------
diff --git a/modules/web-agent/src/main/resources/log4j.properties b/modules/web-agent/src/main/resources/log4j.properties
deleted file mode 100644
index 3b7767c..0000000
--- a/modules/web-agent/src/main/resources/log4j.properties
+++ /dev/null
@@ -1,53 +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.
-
-log4j.rootLogger=INFO,console_err,file
-
-log4j.logger.org.apache.http=WARN
-log4j.logger.org.apache.ignite.spi.checkpoint.noop.NoopCheckpointSpi=OFF
-log4j.logger.org.apache.ignite.spi.swapspace.noop.NoopSwapSpaceSpi=OFF
-log4j.logger.org.apache.ignite.internal.managers.collision.GridCollisionManager=ERROR
-log4j.logger.org.apache.commons.beanutils=WARN
-log4j.logger.sun.net.www.protocol.http=WARN
-
-# Configure console appender.
-log4j.appender.console_err=org.apache.log4j.ConsoleAppender
-log4j.appender.console_err.Threshold=WARN
-log4j.appender.console_err.layout=org.apache.log4j.PatternLayout
-log4j.appender.console_err.layout.ConversionPattern=[%d{ABSOLUTE}][%-5p][%t][%c{1}] %m%n
-
-# Configure console appender.
-log4j.appender.console=org.apache.log4j.ConsoleAppender
-log4j.appender.console.layout=org.apache.log4j.PatternLayout
-log4j.appender.console.layout.ConversionPattern=[%d{ABSOLUTE}][%-5p][%t][%c{1}] %m%n
-log4j.appender.console.filter.a=org.apache.log4j.varia.LevelMatchFilter
-log4j.appender.console.filter.a.LevelToMatch=INFO
-log4j.appender.console.filter.a.AcceptOnMatch=true
-log4j.appender.console.filter.b=org.apache.log4j.varia.LevelMatchFilter
-log4j.appender.console.filter.b.LevelToMatch=ERROR
-log4j.appender.console.filter.b.AcceptOnMatch=false
-log4j.appender.console.filter.c=org.apache.log4j.varia.LevelMatchFilter
-log4j.appender.console.filter.c.LevelToMatch=WARN
-log4j.appender.console.filter.c.AcceptOnMatch=false
-
-log4j.category.org.apache.ignite.console=INFO,console
-
-# Direct log messages to a log file
-log4j.appender.file=org.apache.log4j.RollingFileAppender
-log4j.appender.file.File=logs/ignite-web-agent.log
-log4j.appender.file.MaxFileSize=10MB
-log4j.appender.file.MaxBackupIndex=10
-log4j.appender.file.layout=org.apache.log4j.PatternLayout
-log4j.appender.file.layout.ConversionPattern=[%d{ABSOLUTE}][%-5p][%t][%c{1}] %m%n

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/.gitignore
----------------------------------------------------------------------
diff --git a/modules/web-console/.gitignore b/modules/web-console/.gitignore
new file mode 100644
index 0000000..9ddddc4
--- /dev/null
+++ b/modules/web-console/.gitignore
@@ -0,0 +1,6 @@
+docker/standalone/backend/build
+docker/standalone/frontend/build
+docker/standalone/data
+docker/compose/backend/build
+docker/compose/frontend/build
+docker/dev/data

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/DEVNOTES.txt
----------------------------------------------------------------------
diff --git a/modules/web-console/DEVNOTES.txt b/modules/web-console/DEVNOTES.txt
index 3732b78..27211aa 100644
--- a/modules/web-console/DEVNOTES.txt
+++ b/modules/web-console/DEVNOTES.txt
@@ -13,22 +13,26 @@ How to deploy locally:
        npm install -g npm-windows-upgrade
        npm-windows-upgrade
        See: https://github.com/felixrieseberg/npm-windows-upgrade
-  Check npm version: "npm --version".
-5. Run "npm install --no-optional" in terminal for download dependencies.
-6. Build ignite-web-agent module follow instructions from 'modules/web-agent/README.txt'.
-7. Copy ignite-web-agent-<version>.zip from target of ignite-web-agent module to 'modules/web-console/src/main/js/serve/agent_dists' folder.
+  Check npm version: "npm --version", it should be 3.x.
+5. Change directory to '$IGNITE_HOME/modules/web-console/backend' and
+ run "npm install --no-optional" for download backend dependencies.
+6. Change directory to '$IGNITE_HOME/modules/web-console/frontend' and
+ run "npm install --no-optional" for download frontend dependencies.
+7. Build ignite-web-agent module follow instructions from 'modules/web-agent/README.txt'.
+8. Copy ignite-web-agent-<version>.zip from '$IGNITE_HOME/modules/web-console/web-agent/target'
+ to '$IGNITE_HOME/modules/web-console/backend/agent_dists' folder.
 
-Steps 1 - 7 should be executed once.
+Steps 1 - 8 should be executed once.
 
 How to run console in development mode:
 
 1. Configure MongoDB to run as service or in terminal change dir to $MONGO_INSTALL_DIR/server/3.0/bin
   and start MongoDB by executing "mongod".
 
-2. In new terminal change directory to '$IGNITE_HOME/modules/web-console/src/main/js'.
-   If needed run "npm install --no-optional" (if dependencies changed) and run "node serve" to start backend.
+2. In new terminal change directory to '$IGNITE_HOME/modules/web-console/backend'.
+   If needed run "npm install --no-optional" (if dependencies changed) and run "npm start" to start backend.
 
-3. In new terminal change directory to '$IGNITE_HOME/modules/web-console/src/main/js'
-  and start webpack in development mode "npm run dev" .
+3. In new terminal change directory to '$IGNITE_HOME/modules/web-console/frontend'.
+  If needed run "npm install --no-optional" (if dependencies changed) and start webpack in development mode "npm run dev".
 
 4. In browser open: http://localhost:9000

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/backend/.babelrc
----------------------------------------------------------------------
diff --git a/modules/web-console/backend/.babelrc b/modules/web-console/backend/.babelrc
new file mode 100644
index 0000000..7eb36f4
--- /dev/null
+++ b/modules/web-console/backend/.babelrc
@@ -0,0 +1,9 @@
+{
+  "presets": ["es2015", "stage-1"],
+  "plugins": [[
+    "transform-builtin-extend", {
+      "globals": ["Error", "Array"],
+      "approximate": true
+    }
+  ]]
+}

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/backend/.eslintrc
----------------------------------------------------------------------
diff --git a/modules/web-console/backend/.eslintrc b/modules/web-console/backend/.eslintrc
new file mode 100644
index 0000000..c0c772b
--- /dev/null
+++ b/modules/web-console/backend/.eslintrc
@@ -0,0 +1,188 @@
+parser: "babel-eslint"
+
+env:
+    es6: true
+    node: true
+    mocha: true
+
+ecmaFeatures:
+    arrowFunctions: true
+    blockBindings: true
+    classes: true
+    defaultParams: true
+    destructuring: true
+    module: true
+    objectLiteralComputedProperties: true
+    objectLiteralShorthandMethods: true
+    objectLiteralShorthandProperties: true
+    spread: true
+    templateStrings: true
+    experimentalObjectRestSpread: true
+
+globals:
+    _: true
+    io: true
+
+rules:
+    arrow-parens: [1, "always"]
+    arrow-spacing: [1, { "before": true, "after": true }]
+    accessor-pairs: 2
+    block-scoped-var: 2
+    brace-style: [0, "1tbs"]
+    comma-dangle: [2, "never"]
+    comma-spacing: [2, {"before": false, "after": true}]
+    comma-style: [2, "last"]
+    complexity: [1, 40]
+    computed-property-spacing: [2, "never"]
+    consistent-return: 0
+    consistent-this: [0, "that"]
+    constructor-super: 2
+    curly: [2, "multi-or-nest"]
+    default-case: 2
+    dot-location: 0
+    dot-notation: [2, { "allowKeywords": true }]
+    eol-last: 2
+    eqeqeq: 2
+    func-names: 0
+    func-style: [0, "declaration"]
+    generator-star-spacing: 0
+    guard-for-in: 1
+    handle-callback-err: 0
+    id-length: [2, {"min": 1, "max": 60}]
+    indent: [2, 4, {"SwitchCase": 1}]
+    key-spacing: [2, { "beforeColon": false, "afterColon": true }]
+    lines-around-comment: 0
+    linebreak-style: [0, "unix"]
+    max-depth: [0, 4]
+    max-len: [0, 120, 4]
+    max-nested-callbacks: [1, 4]
+    max-params: [0, 3]
+    max-statements: [0, 10]
+    new-cap: 2
+    new-parens: 2
+    no-alert: 2
+    no-array-constructor: 2
+    no-bitwise: 0
+    no-caller: 2
+    no-catch-shadow: 2
+    no-cond-assign: 2
+    no-console: 0
+    no-constant-condition: 2
+    no-continue: 0
+    no-class-assign: 2
+    no-const-assign: 2
+    no-control-regex: 2
+    no-debugger: 2
+    no-delete-var: 2
+    no-div-regex: 0
+    no-dupe-keys: 2
+    no-dupe-args: 2
+    no-duplicate-case: 2
+    no-else-return: 2
+    no-empty: 2
+    no-empty-character-class: 2
+    no-eq-null: 2
+    no-eval: 2
+    no-ex-assign: 2
+    no-extend-native: 2
+    no-extra-bind: 2
+    no-extra-boolean-cast: 2
+    no-extra-parens: 0
+    no-extra-semi: 2
+    no-fallthrough: 2
+    no-floating-decimal: 1
+    no-func-assign: 2
+    no-implied-eval: 2
+    no-inline-comments: 0
+    no-inner-declarations: [2, "functions"]
+    no-invalid-regexp: 2
+    no-irregular-whitespace: 2
+    no-iterator: 2
+    no-label-var: 2
+    no-labels: 2
+    no-lone-blocks: 2
+    no-lonely-if: 2
+    no-implicit-coercion: [2, {"boolean": false, "number": true, "string": true}]
+    no-loop-func: 2
+    no-mixed-requires: [0, false]
+    no-mixed-spaces-and-tabs: [2, true]
+    no-multi-spaces: 2
+    no-multi-str: 2
+    no-multiple-empty-lines: [0, {"max": 2}]
+    no-native-reassign: 2
+    no-negated-in-lhs: 2
+    no-nested-ternary: 0
+    no-new: 2
+    no-new-func: 2
+    no-new-object: 2
+    no-new-require: 0
+    no-new-wrappers: 2
+    no-obj-calls: 2
+    no-octal: 2
+    no-octal-escape: 2
+    no-param-reassign: 0
+    no-path-concat: 0
+    no-plusplus: 0
+    no-process-env: 0
+    no-process-exit: 1
+    no-proto: 2
+    no-redeclare: 2
+    no-regex-spaces: 1
+    no-restricted-modules: 0
+    no-script-url: 0
+    no-self-compare: 2
+    no-sequences: 2
+    no-shadow: 2
+    no-shadow-restricted-names: 2
+    no-spaced-func: 2
+    no-sparse-arrays: 1
+    no-sync: 0
+    no-ternary: 0
+    no-trailing-spaces: 2
+    no-throw-literal: 0
+    no-this-before-super: 2
+    no-unexpected-multiline: 2
+    no-undef: 2
+    no-undef-init: 2
+    no-undefined: 2
+    no-unneeded-ternary: 2
+    no-unreachable: 2
+    no-unused-expressions: [2, { allowShortCircuit: true }]
+    no-unused-vars: [2, {"vars": "all", "args": "after-used"}]
+    no-use-before-define: 2
+    no-useless-call: 2
+    no-void: 0
+    no-var: 2
+    no-warning-comments: 0
+    no-with: 2
+    newline-after-var: 0
+    object-shorthand: [2, "always"]
+    one-var: [2, "never"]
+    operator-assignment: [2, "always"]
+    operator-linebreak: 0
+    padded-blocks: 0
+    prefer-const: 1
+    prefer-spread: 2
+    quote-props: [2, "as-needed"]
+    quotes: [2, "single"]
+    radix: 1
+    semi: [2, "always"]
+    semi-spacing: [2, {"before": false, "after": true}]
+    sort-vars: 0
+    keyword-spacing: 2
+    space-before-blocks: [2, "always"]
+    space-before-function-paren: [2, "never"]
+    space-in-parens: 0
+    space-infix-ops: 2
+    space-unary-ops: [2, { "words": true, "nonwords": false }]
+    spaced-comment: [1, "always"]
+    use-isnan: 2
+    valid-jsdoc: 0
+    valid-typeof: 2
+    vars-on-top: 2
+    wrap-iife: 0
+    wrap-regex: 0
+    yoda: [2, "never"]
+
+parserOptions:
+    sourceType: module

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/backend/.gitignore
----------------------------------------------------------------------
diff --git a/modules/web-console/backend/.gitignore b/modules/web-console/backend/.gitignore
new file mode 100644
index 0000000..f95e2bf
--- /dev/null
+++ b/modules/web-console/backend/.gitignore
@@ -0,0 +1,8 @@
+*.idea
+*.log
+.npmrc
+node_modules
+serve/config/*.json
+serve/agent_dists/*.zip
+agent_dists/*.zip
+config/*.json

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/backend/agent_dists/README.txt
----------------------------------------------------------------------
diff --git a/modules/web-console/backend/agent_dists/README.txt b/modules/web-console/backend/agent_dists/README.txt
new file mode 100644
index 0000000..d51bdf9
--- /dev/null
+++ b/modules/web-console/backend/agent_dists/README.txt
@@ -0,0 +1,7 @@
+Ignite Web Console
+======================================
+
+This is default folder for agent distributives.
+
+Also, you could specify custom folder in `serve/config/settings.json`
+


[47/52] ignite git commit: Web Console beta-3.

Posted by ak...@apache.org.
Web Console beta-3.


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

Branch: refs/heads/master
Commit: 6af6560a4c90ac24644991ce25081c7548279aa6
Parents: afac3fa
Author: Alexey Kuznetsov <ak...@apache.org>
Authored: Thu Sep 8 14:43:57 2016 +0700
Committer: Alexey Kuznetsov <ak...@apache.org>
Committed: Thu Sep 8 14:44:04 2016 +0700

----------------------------------------------------------------------
 .../visor/event/VisorGridDiscoveryEventV2.java  |   80 +
 .../visor/node/VisorNodeDataCollectorJob.java   |   10 +-
 .../internal/visor/util/VisorEventMapper.java   |   96 +-
 .../internal/visor/util/VisorTaskUtils.java     |   22 +-
 modules/web-agent/.gitignore                    |    2 -
 modules/web-agent/README.txt                    |   88 -
 .../web-agent/assembly/release-web-agent.xml    |   72 -
 modules/web-agent/bin/ignite-web-agent.bat      |   70 -
 modules/web-agent/bin/ignite-web-agent.sh       |   87 -
 modules/web-agent/demo/README.txt               |    4 -
 modules/web-agent/demo/db-init.sql              |  102 -
 modules/web-agent/jdbc-drivers/README.txt       |   10 -
 modules/web-agent/logs/README.txt               |    5 -
 modules/web-agent/pom.xml                       |  189 -
 .../console/agent/AgentConfiguration.java       |  268 --
 .../ignite/console/agent/AgentLauncher.java     |  344 --
 .../apache/ignite/console/agent/AgentUtils.java |  111 -
 .../console/agent/handlers/AbstractHandler.java |  110 -
 .../console/agent/handlers/DatabaseHandler.java |  298 --
 .../console/agent/handlers/RestHandler.java     |  276 --
 .../ignite/console/demo/AgentClusterDemo.java   |  638 ----
 .../ignite/console/demo/AgentMetadataDemo.java  |   92 -
 .../apache/ignite/console/demo/model/Car.java   |  152 -
 .../ignite/console/demo/model/Country.java      |  152 -
 .../ignite/console/demo/model/Department.java   |  152 -
 .../ignite/console/demo/model/Employee.java     |  356 --
 .../ignite/console/demo/model/Parking.java      |  152 -
 .../src/main/resources/log4j.properties         |   53 -
 modules/web-console/.gitignore                  |    6 +
 modules/web-console/DEVNOTES.txt                |   22 +-
 modules/web-console/backend/.babelrc            |    9 +
 modules/web-console/backend/.eslintrc           |  188 +
 modules/web-console/backend/.gitignore          |    8 +
 .../web-console/backend/agent_dists/README.txt  |    7 +
 modules/web-console/backend/app/agent.js        |  753 ++++
 modules/web-console/backend/app/app.js          |   61 +
 modules/web-console/backend/app/browser.js      |  404 ++
 modules/web-console/backend/app/configure.js    |   86 +
 modules/web-console/backend/app/index.js        |  116 +
 modules/web-console/backend/app/mongo.js        |  673 ++++
 modules/web-console/backend/app/nconf.js        |   48 +
 modules/web-console/backend/app/routes.js       |   64 +
 modules/web-console/backend/app/settings.js     |   80 +
 .../backend/config/settings.json.sample         |   30 +
 .../backend/errors/AppErrorException.js         |   36 +
 .../backend/errors/AuthFailedException.js       |   30 +
 .../backend/errors/DuplicateKeyException.js     |   28 +
 .../backend/errors/IllegalAccessError.js        |   29 +
 .../backend/errors/IllegalArgumentException.js  |   29 +
 .../backend/errors/MissingResourceException.js  |   30 +
 .../backend/errors/ServerErrorException.js      |   36 +
 modules/web-console/backend/errors/index.js     |   39 +
 modules/web-console/backend/index.js            |   19 +
 modules/web-console/backend/injector.js         |   30 +
 modules/web-console/backend/middlewares/api.js  |   44 +
 modules/web-console/backend/middlewares/host.js |   39 +
 modules/web-console/backend/middlewares/user.js |   36 +
 modules/web-console/backend/package.json        |   71 +
 modules/web-console/backend/routes/admin.js     |   84 +
 modules/web-console/backend/routes/agent.js     |   53 +
 modules/web-console/backend/routes/caches.js    |   65 +
 modules/web-console/backend/routes/clusters.js  |   64 +
 .../web-console/backend/routes/configuration.js |   41 +
 modules/web-console/backend/routes/demo.js      |  133 +
 .../web-console/backend/routes/demo/caches.json |   87 +
 .../backend/routes/demo/clusters.json           |   50 +
 .../backend/routes/demo/domains.json            |  307 ++
 .../web-console/backend/routes/demo/igfss.json  |   10 +
 modules/web-console/backend/routes/domains.js   |   76 +
 modules/web-console/backend/routes/igfss.js     |   65 +
 modules/web-console/backend/routes/notebooks.js |   80 +
 modules/web-console/backend/routes/profile.js   |   73 +
 modules/web-console/backend/routes/public.js    |  168 +
 modules/web-console/backend/services/agents.js  |   82 +
 modules/web-console/backend/services/auth.js    |   47 +
 modules/web-console/backend/services/caches.js  |  144 +
 .../web-console/backend/services/clusters.js    |  141 +
 .../backend/services/configurations.js          |   59 +
 modules/web-console/backend/services/domains.js |  187 +
 modules/web-console/backend/services/igfss.js   |  136 +
 modules/web-console/backend/services/mails.js   |  131 +
 .../web-console/backend/services/notebooks.js   |  104 +
 .../web-console/backend/services/sessions.js    |   63 +
 modules/web-console/backend/services/spaces.js  |   75 +
 modules/web-console/backend/services/users.js   |  229 ++
 .../backend/test/config/settings.json           |   20 +
 .../web-console/backend/test/data/accounts.json |   18 +
 .../web-console/backend/test/data/caches.json   |   87 +
 .../web-console/backend/test/data/clusters.json |   50 +
 .../web-console/backend/test/data/domains.json  |  307 ++
 .../web-console/backend/test/data/igfss.json    |   10 +
 modules/web-console/backend/test/injector.js    |   31 +
 .../backend/test/unit/CacheService.test.js      |  192 +
 .../backend/test/unit/ClusterService.test.js    |  190 +
 .../backend/test/unit/DomainService.test.js     |  198 +
 .../backend/test/unit/IgfsService.test.js       |  190 +
 .../docker/compose/backend/.dockerignore        |    1 +
 .../docker/compose/backend/Dockerfile           |   30 +
 .../web-console/docker/compose/backend/build.sh |   57 +
 .../docker/compose/docker-compose.yml           |   59 +
 .../docker/compose/frontend/.dockerignore       |    3 +
 .../docker/compose/frontend/Dockerfile          |   32 +
 .../docker/compose/frontend/DockerfileBuild     |   30 +
 .../docker/compose/frontend/build.sh            |   59 +
 .../docker/compose/frontend/nginx/nginx.conf    |   57 +
 .../compose/frontend/nginx/web-console.conf     |   59 +
 .../web-console/docker/standalone/.dockerignore |    2 +
 .../web-console/docker/standalone/Dockerfile    |   87 +
 modules/web-console/docker/standalone/build.sh  |   59 +
 .../docker/standalone/docker-compose.yml        |   41 +
 .../web-console/docker/standalone/entrypoint.sh |   23 +
 .../docker/standalone/nginx/nginx.conf          |   55 +
 .../docker/standalone/nginx/web-console.conf    |   54 +
 modules/web-console/frontend/.babelrc           |    9 +
 modules/web-console/frontend/.eslintrc          |  202 +
 modules/web-console/frontend/.gitignore         |    7 +
 modules/web-console/frontend/app/app.config.js  |   86 +
 modules/web-console/frontend/app/app.js         |  270 ++
 .../frontend/app/controllers/auth.controller.js |   30 +
 .../controllers/reset-password.controller.js    |   50 +
 .../web-console/frontend/app/data/colors.json   |   22 +
 .../frontend/app/data/countries.json            |   94 +
 .../frontend/app/data/demo-info.json            |   14 +
 .../frontend/app/data/event-types.json          |  169 +
 .../frontend/app/data/getting-started.json      |  109 +
 .../frontend/app/data/java-classes.json         |   19 +
 .../frontend/app/data/java-keywords.json        |   55 +
 .../frontend/app/data/java-primitives.json      |    9 +
 .../frontend/app/data/pom-dependencies.json     |   20 +
 .../frontend/app/decorator/select.js            |   77 +
 .../frontend/app/decorator/tooltip.js           |   56 +
 .../app/directives/auto-focus.directive.js      |   26 +
 .../app/directives/bs-affix-update.directive.js |   34 +
 .../app/directives/centered/centered.css        |   37 +
 .../directives/centered/centered.directive.js   |   26 +
 .../directives/copy-to-clipboard.directive.js   |   29 +
 .../hide-on-state-change.directive.js           |   31 +
 .../information/information.directive.js        |   30 +
 .../app/directives/information/information.jade |   20 +
 .../app/directives/information/information.scss |   56 +
 .../frontend/app/directives/match.directive.js  |   27 +
 .../app/directives/on-click-focus.directive.js  |   26 +
 .../directives/on-enter-focus-move.directive.js |   29 +
 .../app/directives/on-enter.directive.js        |   32 +
 .../app/directives/on-escape.directive.js       |   32 +
 .../ui-ace-docker/ui-ace-docker.controller.js   |   33 +
 .../ui-ace-docker/ui-ace-docker.directive.js    |   46 +
 .../directives/ui-ace-docker/ui-ace-docker.jade |   31 +
 .../ui-ace-java/ui-ace-java.controller.js       |   32 +
 .../ui-ace-java/ui-ace-java.directive.js        |  147 +
 .../app/directives/ui-ace-java/ui-ace-java.jade |   22 +
 .../ui-ace-pojos/ui-ace-pojos.controller.js     |   95 +
 .../ui-ace-pojos/ui-ace-pojos.directive.js      |   46 +
 .../directives/ui-ace-pojos/ui-ace-pojos.jade   |   40 +
 .../ui-ace-pom/ui-ace-pom.controller.js         |   33 +
 .../ui-ace-pom/ui-ace-pom.directive.js          |   41 +
 .../app/directives/ui-ace-pom/ui-ace-pom.jade   |   17 +
 .../app/directives/ui-ace-tabs.directive.js     |   24 +
 .../ui-ace-xml/ui-ace-xml.controller.js         |   27 +
 .../ui-ace-xml/ui-ace-xml.directive.js          |  147 +
 .../app/directives/ui-ace-xml/ui-ace-xml.jade   |   17 +
 .../frontend/app/filters/byName.filter.js       |   23 +
 .../app/filters/domainsValidation.filter.js     |   33 +
 .../frontend/app/filters/duration.filter.js     |   38 +
 .../frontend/app/filters/hasPojo.filter.js      |   18 +
 .../frontend/app/helpers/jade/form.jade         |   27 +
 .../helpers/jade/form/form-field-checkbox.jade  |   38 +
 .../helpers/jade/form/form-field-datalist.jade  |   51 +
 .../app/helpers/jade/form/form-field-down.jade  |   18 +
 .../helpers/jade/form/form-field-dropdown.jade  |   50 +
 .../helpers/jade/form/form-field-feedback.jade  |   29 +
 .../app/helpers/jade/form/form-field-label.jade |   23 +
 .../helpers/jade/form/form-field-number.jade    |   52 +
 .../app/helpers/jade/form/form-field-text.jade  |   47 +
 .../app/helpers/jade/form/form-field-up.jade    |   18 +
 .../app/helpers/jade/form/form-group.jade       |   23 +
 .../frontend/app/helpers/jade/mixins.jade       |  541 +++
 .../frontend/app/modules/Demo/Demo.module.js    |  166 +
 .../frontend/app/modules/ace.module.js          |  269 ++
 .../frontend/app/modules/agent/agent.module.js  |  341 ++
 .../app/modules/branding/branding.module.js     |   45 +
 .../app/modules/branding/branding.provider.js   |  111 +
 .../app/modules/branding/features.directive.js  |   35 +
 .../app/modules/branding/footer.directive.js    |   34 +
 .../modules/branding/header-logo.directive.js   |   34 +
 .../app/modules/branding/header-logo.jade       |   18 +
 .../modules/branding/header-title.directive.js  |   35 +
 .../branding/powered-by-apache.directive.js     |   35 +
 .../app/modules/branding/powered-by-apache.jade |   18 +
 .../app/modules/branding/terms.directive.js     |   30 +
 .../configuration/EventGroups.provider.js       |   30 +
 .../modules/configuration/Sidebar.provider.js   |   39 +
 .../configuration/configuration.module.js       |   41 +
 .../configuration/generator/Docker.service.js   |   78 +
 .../configuration/generator/Java.service.js     |   21 +
 .../configuration/generator/Pom.service.js      |  226 ++
 .../configuration/generator/Xml.service.js      |   21 +
 .../modules/configuration/sidebar.directive.js  |   30 +
 .../modules/dialog/dialog-content.directive.js  |   31 +
 .../modules/dialog/dialog-title.directive.js    |   31 +
 .../app/modules/dialog/dialog.controller.js     |   40 +
 .../app/modules/dialog/dialog.directive.js      |   32 +
 .../app/modules/dialog/dialog.factory.js        |   32 +
 .../frontend/app/modules/dialog/dialog.jade     |   26 +
 .../app/modules/dialog/dialog.module.js         |   32 +
 .../field/bs-select-placeholder.directive.js    |   47 +
 .../app/modules/form/field/down.directive.js    |   39 +
 .../app/modules/form/field/feedback.scss        |   37 +
 .../frontend/app/modules/form/field/field.scss  |   43 +
 .../field/form-control-feedback.directive.js    |   40 +
 .../form/field/input/autofocus.directive.js     |   30 +
 .../app/modules/form/field/input/select.scss    |   21 +
 .../app/modules/form/field/input/text.scss      |   41 +
 .../app/modules/form/field/label.directive.js   |   47 +
 .../app/modules/form/field/tooltip.directive.js |   49 +
 .../app/modules/form/field/up.directive.js      |   39 +
 .../frontend/app/modules/form/form.module.js    |   96 +
 .../app/modules/form/group/add.directive.js     |   40 +
 .../app/modules/form/group/tooltip.directive.js |   40 +
 .../app/modules/form/panel/chevron.directive.js |   53 +
 .../app/modules/form/panel/field.directive.js   |   69 +
 .../app/modules/form/panel/panel.directive.js   |   37 +
 .../app/modules/form/panel/revert.directive.js  |   54 +
 .../form/validator/ipaddress.directive.js       |   86 +
 .../validator/java-built-in-class.directive.js  |   31 +
 .../form/validator/java-identifier.directive.js |   31 +
 .../form/validator/java-keywords.directive.js   |   42 +
 .../validator/java-package-name.directive.js    |   31 +
 .../java-package-specified.directive.js         |   34 +
 .../form/validator/property-unique.directive.js |   47 +
 .../property-value-specified.directive.js       |   31 +
 .../modules/form/validator/unique.directive.js  |   49 +
 .../modules/form/validator/uuid.directive.js    |   37 +
 .../getting-started/GettingStarted.provider.js  |  112 +
 .../frontend/app/modules/loading/loading.css    |   73 +
 .../app/modules/loading/loading.directive.js    |   51 +
 .../frontend/app/modules/loading/loading.jade   |   23 +
 .../app/modules/loading/loading.module.js       |   26 +
 .../app/modules/loading/loading.service.js      |   48 +
 .../app/modules/navbar/Navbar.provider.js       |   28 +
 .../app/modules/navbar/Userbar.provider.js      |   28 +
 .../app/modules/navbar/navbar.directive.js      |   30 +
 .../app/modules/navbar/navbar.module.js         |   33 +
 .../app/modules/navbar/userbar.directive.js     |   48 +
 .../frontend/app/modules/socket.module.js       |   41 +
 .../frontend/app/modules/sql/Notebook.data.js   |  157 +
 .../app/modules/sql/Notebook.service.js         |   74 +
 .../app/modules/sql/notebook.controller.js      |   60 +
 .../app/modules/sql/scan-filter-input.jade      |   39 +
 .../modules/sql/scan-filter-input.service.js    |   51 +
 .../frontend/app/modules/sql/sql.controller.js  | 1632 ++++++++
 .../frontend/app/modules/sql/sql.module.js      |   60 +
 .../frontend/app/modules/states/admin.state.js  |   35 +
 .../app/modules/states/configuration.state.js   |   97 +
 .../configuration/Configuration.resource.js     |   42 +
 .../configuration/caches/concurrency.jade       |   65 +
 .../states/configuration/caches/general.jade    |   66 +
 .../states/configuration/caches/memory.jade     |  102 +
 .../configuration/caches/node-filter.jade       |  108 +
 .../states/configuration/caches/query.jade      |   95 +
 .../states/configuration/caches/rebalance.jade  |   65 +
 .../configuration/caches/server-near-cache.jade |   51 +
 .../states/configuration/caches/statistics.jade |   39 +
 .../states/configuration/caches/store.jade      |  244 ++
 .../states/configuration/clusters/atomic.jade   |   53 +
 .../configuration/clusters/attributes.jade      |   57 +
 .../states/configuration/clusters/binary.jade   |   77 +
 .../configuration/clusters/cache-key-cfg.jade   |   53 +
 .../configuration/clusters/collision.jade       |   62 +
 .../clusters/collision/custom.jade              |   24 +
 .../clusters/collision/fifo-queue.jade          |   27 +
 .../clusters/collision/job-stealing.jade        |   63 +
 .../clusters/collision/priority-queue.jade      |   42 +
 .../configuration/clusters/communication.jade   |   99 +
 .../configuration/clusters/connector.jade       |  103 +
 .../configuration/clusters/deployment.jade      |  113 +
 .../configuration/clusters/discovery.jade       |   87 +
 .../states/configuration/clusters/events.jade   |   37 +
 .../states/configuration/clusters/failover.jade |   72 +
 .../states/configuration/clusters/general.jade  |   73 +
 .../clusters/general/discovery/cloud.jade       |  134 +
 .../clusters/general/discovery/google.jade      |   38 +
 .../clusters/general/discovery/jdbc.jade        |   32 +
 .../clusters/general/discovery/multicast.jade   |   99 +
 .../clusters/general/discovery/s3.jade          |   27 +
 .../clusters/general/discovery/shared.jade      |   23 +
 .../clusters/general/discovery/vm.jade          |   79 +
 .../clusters/general/discovery/zookeeper.jade   |   83 +
 .../bounded-exponential-backoff.jade            |   27 +
 .../discovery/zookeeper/retrypolicy/custom.jade |   24 +
 .../retrypolicy/exponential-backoff.jade        |   27 +
 .../zookeeper/retrypolicy/forever.jade          |   22 +
 .../zookeeper/retrypolicy/n-times.jade          |   25 +
 .../zookeeper/retrypolicy/one-time.jade         |   23 +
 .../zookeeper/retrypolicy/until-elapsed.jade    |   25 +
 .../states/configuration/clusters/igfs.jade     |   37 +
 .../states/configuration/clusters/logger.jade   |   66 +
 .../configuration/clusters/logger/custom.jade   |   25 +
 .../configuration/clusters/logger/log4j.jade    |   50 +
 .../configuration/clusters/logger/log4j2.jade   |   39 +
 .../configuration/clusters/marshaller.jade      |   75 +
 .../states/configuration/clusters/metrics.jade  |   51 +
 .../states/configuration/clusters/ssl.jade      |  109 +
 .../states/configuration/clusters/swap.jade     |   71 +
 .../states/configuration/clusters/thread.jade   |   48 +
 .../states/configuration/clusters/time.jade     |   47 +
 .../configuration/clusters/transactions.jade    |   69 +
 .../states/configuration/domains/general.jade   |   46 +
 .../states/configuration/domains/query.jade     |  170 +
 .../states/configuration/domains/store.jade     |  126 +
 .../modules/states/configuration/igfs/dual.jade |   42 +
 .../states/configuration/igfs/fragmentizer.jade |   43 +
 .../states/configuration/igfs/general.jade      |   54 +
 .../modules/states/configuration/igfs/ipc.jade  |   60 +
 .../modules/states/configuration/igfs/misc.jade |  108 +
 .../states/configuration/igfs/secondary.jade    |   44 +
 .../configuration/preview-panel.directive.js    |  239 ++
 .../summary/summary-tabs.directive.js           |   50 +
 .../configuration/summary/summary.controller.js |  365 ++
 .../frontend/app/modules/states/errors.state.js |   43 +
 .../frontend/app/modules/states/logout.state.js |   35 +
 .../app/modules/states/password.state.js        |   46 +
 .../app/modules/states/profile.state.js         |   35 +
 .../frontend/app/modules/states/signin.state.js |   43 +
 .../app/modules/user/AclRoute.provider.js       |   47 +
 .../frontend/app/modules/user/Auth.service.js   |   56 +
 .../frontend/app/modules/user/User.service.js   |   51 +
 .../frontend/app/modules/user/permissions.js    |   28 +
 .../frontend/app/modules/user/user.module.js    |   73 +
 .../app/modules/version/Version.provider.js     |   32 +
 .../app/services/ChartColors.service.js         |   22 +
 .../frontend/app/services/Clone.service.js      |   64 +
 .../frontend/app/services/Confirm.service.js    |   68 +
 .../app/services/ConfirmBatch.service.js        |   92 +
 .../app/services/CopyToClipboard.service.js     |   50 +
 .../frontend/app/services/Countries.service.js  |   31 +
 .../app/services/ErrorPopover.service.js        |  126 +
 .../frontend/app/services/Focus.service.js      |   33 +
 .../frontend/app/services/FormUtils.service.js  |  435 +++
 .../app/services/InetAddress.service.js         |   53 +
 .../frontend/app/services/JavaTypes.service.js  |   93 +
 .../app/services/LegacyTable.service.js         |  209 ++
 .../app/services/LegacyUtils.service.js         |  572 +++
 .../frontend/app/services/Messages.service.js   |   63 +
 .../app/services/ModelNormalizer.service.js     |   59 +
 .../app/services/UnsavedChangesGuard.service.js |   38 +
 modules/web-console/frontend/app/vendor.js      |   55 +
 .../frontend/controllers/admin-controller.js    |   92 +
 .../frontend/controllers/caches-controller.js   |  524 +++
 .../frontend/controllers/clusters-controller.js |  689 ++++
 .../frontend/controllers/domains-controller.js  | 1790 +++++++++
 .../frontend/controllers/igfs-controller.js     |  416 +++
 .../frontend/controllers/profile-controller.js  |   94 +
 .../frontend/generator/generator-common.js      |  612 +++
 .../frontend/generator/generator-java.js        | 3534 ++++++++++++++++++
 .../frontend/generator/generator-optional.js    |   25 +
 .../frontend/generator/generator-properties.js  |  175 +
 .../frontend/generator/generator-readme.js      |   85 +
 .../frontend/generator/generator-xml.js         | 2093 +++++++++++
 .../frontend/gulpfile.babel.js/index.js         |   26 +
 .../frontend/gulpfile.babel.js/paths.js         |   74 +
 .../frontend/gulpfile.babel.js/tasks/build.js   |   21 +
 .../frontend/gulpfile.babel.js/tasks/bundle.js  |   32 +
 .../frontend/gulpfile.babel.js/tasks/clean.js   |   32 +
 .../frontend/gulpfile.babel.js/tasks/copy.js    |   33 +
 .../gulpfile.babel.js/tasks/ignite-modules.js   |   55 +
 .../frontend/gulpfile.babel.js/tasks/jade.js    |   40 +
 .../frontend/gulpfile.babel.js/tasks/test.js    |   92 +
 .../frontend/gulpfile.babel.js/tasks/watch.js   |   31 +
 .../gulpfile.babel.js/webpack/common.js         |  189 +
 .../webpack/environments/development.js         |   69 +
 .../webpack/environments/production.js          |   45 +
 .../frontend/gulpfile.babel.js/webpack/index.js |   32 +
 .../webpack/plugins/progress.js                 |   82 +
 .../frontend/ignite_modules/README.txt          |    6 +
 .../frontend/ignite_modules/index.js            |   27 +
 modules/web-console/frontend/package.json       |  125 +
 modules/web-console/frontend/public/favicon.ico |  Bin 0 -> 1150 bytes
 .../frontend/public/images/cache.png            |  Bin 0 -> 23700 bytes
 .../frontend/public/images/cluster.png          |  Bin 0 -> 29376 bytes
 .../frontend/public/images/docker.png           |  Bin 0 -> 521 bytes
 .../frontend/public/images/domains.png          |  Bin 0 -> 23828 bytes
 .../web-console/frontend/public/images/igfs.png |  Bin 0 -> 14307 bytes
 .../frontend/public/images/ignite-logo.png      |  Bin 0 -> 1982 bytes
 .../frontend/public/images/ignite-logo@2x.png   |  Bin 0 -> 3325 bytes
 .../frontend/public/images/ignite-puzzle.png    |  Bin 0 -> 71974 bytes
 .../web-console/frontend/public/images/java.png |  Bin 0 -> 170 bytes
 .../frontend/public/images/pb-ignite.png        |  Bin 0 -> 3493 bytes
 .../frontend/public/images/pb-ignite@2x.png     |  Bin 0 -> 8558 bytes
 .../frontend/public/images/query-chart.png      |  Bin 0 -> 16637 bytes
 .../frontend/public/images/query-metadata.png   |  Bin 0 -> 32298 bytes
 .../frontend/public/images/query-table.png      |  Bin 0 -> 29189 bytes
 .../frontend/public/images/summary.png          |  Bin 0 -> 31997 bytes
 .../web-console/frontend/public/images/xml.png  |  Bin 0 -> 232 bytes
 .../public/stylesheets/_bootstrap-custom.scss   |   65 +
 .../stylesheets/_bootstrap-variables.scss       |  891 +++++
 .../stylesheets/_font-awesome-custom.scss       |   32 +
 .../public/stylesheets/blocks/error.scss        |   31 +
 .../frontend/public/stylesheets/style.scss      | 2171 +++++++++++
 .../frontend/public/stylesheets/variables.scss  |   28 +
 .../frontend/test/e2e/exampe.test.js            |   40 +
 modules/web-console/frontend/test/karma.conf.js |  113 +
 .../frontend/test/protractor.conf.js            |   50 +
 .../frontend/test/unit/JavaTypes.test.js        |   69 +
 .../frontend/test/unit/UserAuth.test.js         |   35 +
 modules/web-console/frontend/views/403.jade     |   22 +
 modules/web-console/frontend/views/404.jade     |   22 +
 modules/web-console/frontend/views/base.jade    |   22 +
 .../frontend/views/configuration/caches.jade    |   53 +
 .../frontend/views/configuration/clusters.jade  |   66 +
 .../views/configuration/domains-import.jade     |  223 ++
 .../frontend/views/configuration/domains.jade   |   66 +
 .../frontend/views/configuration/igfs.jade      |   51 +
 .../frontend/views/configuration/sidebar.jade   |   29 +
 .../summary-project-structure.jade              |   27 +
 .../views/configuration/summary-tabs.jade       |   25 +
 .../frontend/views/configuration/summary.jade   |  122 +
 .../frontend/views/includes/footer.jade         |   23 +
 .../frontend/views/includes/header.jade         |   51 +
 modules/web-console/frontend/views/index.jade   |   47 +
 modules/web-console/frontend/views/reset.jade   |   48 +
 .../frontend/views/settings/admin.jade          |   76 +
 .../frontend/views/settings/profile.jade        |   76 +
 modules/web-console/frontend/views/signin.jade  |  163 +
 .../frontend/views/sql/cache-metadata.jade      |   40 +
 .../frontend/views/sql/chart-settings.jade      |   40 +
 .../frontend/views/sql/notebook-new.jade        |   31 +
 .../frontend/views/sql/paragraph-rate.jade      |   31 +
 modules/web-console/frontend/views/sql/sql.jade |  193 +
 .../views/templates/agent-download.jade         |   48 +
 .../frontend/views/templates/alert.jade         |   21 +
 .../frontend/views/templates/batch-confirm.jade |   32 +
 .../frontend/views/templates/clone.jade         |   37 +
 .../frontend/views/templates/confirm.jade       |   31 +
 .../frontend/views/templates/demo-info.jade     |   45 +
 .../frontend/views/templates/dropdown.jade      |   24 +
 .../views/templates/getting-started.jade        |   32 +
 .../frontend/views/templates/message.jade       |   26 +
 .../frontend/views/templates/pagination.jade    |   32 +
 .../frontend/views/templates/select.jade        |   26 +
 .../views/templates/validation-error.jade       |   25 +
 modules/web-console/pom.xml                     |   33 +-
 modules/web-console/src/main/js/.babelrc        |    3 -
 modules/web-console/src/main/js/.eslintrc       |  202 -
 modules/web-console/src/main/js/.gitignore      |    9 -
 .../web-console/src/main/js/app/app.config.js   |   86 -
 modules/web-console/src/main/js/app/app.js      |  274 --
 .../main/js/app/controllers/auth.controller.js  |   30 -
 .../js/app/controllers/notebooks.controller.js  |   69 -
 .../controllers/reset-password.controller.js    |   51 -
 .../src/main/js/app/data/colors.json            |   22 -
 .../src/main/js/app/data/countries.json         |   94 -
 .../src/main/js/app/data/demo-info.json         |   14 -
 .../src/main/js/app/data/event-types.json       |  169 -
 .../src/main/js/app/data/getting-started.json   |  109 -
 .../src/main/js/app/data/java-classes.json      |   18 -
 .../src/main/js/app/data/java-keywords.json     |   55 -
 .../src/main/js/app/data/java-primitives.json   |    9 -
 .../src/main/js/app/data/pom-dependencies.json  |   20 -
 .../src/main/js/app/decorator/select.js         |   77 -
 .../src/main/js/app/decorator/tooltip.js        |   56 -
 .../js/app/directives/auto-focus.directive.js   |   26 -
 .../app/directives/bs-affix-update.directive.js |   34 -
 .../js/app/directives/centered/centered.css     |   37 -
 .../directives/centered/centered.directive.js   |   26 -
 .../directives/copy-to-clipboard.directive.js   |   29 -
 .../hide-on-state-change.directive.js           |   31 -
 .../information/information.directive.js        |   30 -
 .../app/directives/information/information.jade |   20 -
 .../app/directives/information/information.scss |   56 -
 .../main/js/app/directives/match.directive.js   |   27 -
 .../app/directives/on-click-focus.directive.js  |   26 -
 .../directives/on-enter-focus-move.directive.js |   29 -
 .../js/app/directives/on-enter.directive.js     |   32 -
 .../js/app/directives/on-escape.directive.js    |   32 -
 .../ui-ace-docker/ui-ace-docker.controller.js   |   33 -
 .../ui-ace-docker/ui-ace-docker.directive.js    |   46 -
 .../directives/ui-ace-docker/ui-ace-docker.jade |   31 -
 .../ui-ace-java/ui-ace-java.controller.js       |   32 -
 .../ui-ace-java/ui-ace-java.directive.js        |  133 -
 .../app/directives/ui-ace-java/ui-ace-java.jade |   22 -
 .../ui-ace-pojos/ui-ace-pojos.controller.js     |   95 -
 .../ui-ace-pojos/ui-ace-pojos.directive.js      |   46 -
 .../directives/ui-ace-pojos/ui-ace-pojos.jade   |   40 -
 .../ui-ace-pom/ui-ace-pom.controller.js         |   33 -
 .../ui-ace-pom/ui-ace-pom.directive.js          |   41 -
 .../app/directives/ui-ace-pom/ui-ace-pom.jade   |   17 -
 .../js/app/directives/ui-ace-tabs.directive.js  |   23 -
 .../ui-ace-xml/ui-ace-xml.controller.js         |   27 -
 .../ui-ace-xml/ui-ace-xml.directive.js          |  133 -
 .../app/directives/ui-ace-xml/ui-ace-xml.jade   |   17 -
 .../src/main/js/app/filters/byName.filter.js    |   23 -
 .../js/app/filters/domainsValidation.filter.js  |   33 -
 .../src/main/js/app/filters/hasPojo.filter.js   |   18 -
 .../src/main/js/app/helpers/jade/mixins.jade    |  588 ---
 .../src/main/js/app/modules/Demo/Demo.module.js |  166 -
 .../js/app/modules/Version/Version.provider.js  |   32 -
 .../src/main/js/app/modules/ace.module.js       |  269 --
 .../main/js/app/modules/agent/agent.module.js   |  323 --
 .../js/app/modules/branding/branding.module.js  |   45 -
 .../app/modules/branding/branding.provider.js   |  111 -
 .../app/modules/branding/features.directive.js  |   35 -
 .../js/app/modules/branding/footer.directive.js |   34 -
 .../modules/branding/header-logo.directive.js   |   34 -
 .../js/app/modules/branding/header-logo.jade    |   18 -
 .../modules/branding/header-title.directive.js  |   35 -
 .../branding/powered-by-apache.directive.js     |   35 -
 .../app/modules/branding/powered-by-apache.jade |   18 -
 .../js/app/modules/branding/terms.directive.js  |   30 -
 .../configuration/EventGroups.provider.js       |   30 -
 .../modules/configuration/Sidebar.provider.js   |   39 -
 .../configuration/configuration.module.js       |   41 -
 .../configuration/generator/Docker.service.js   |   78 -
 .../configuration/generator/Java.service.js     |   21 -
 .../configuration/generator/Pom.service.js      |  210 --
 .../configuration/generator/Xml.service.js      |   21 -
 .../modules/configuration/sidebar.directive.js  |   30 -
 .../modules/dialog/dialog-content.directive.js  |   31 -
 .../modules/dialog/dialog-title.directive.js    |   31 -
 .../js/app/modules/dialog/dialog.controller.js  |   40 -
 .../js/app/modules/dialog/dialog.directive.js   |   32 -
 .../js/app/modules/dialog/dialog.factory.js     |   32 -
 .../src/main/js/app/modules/dialog/dialog.jade  |   26 -
 .../main/js/app/modules/dialog/dialog.module.js |   32 -
 .../field/bs-select-placeholder.directive.js    |   47 -
 .../js/app/modules/form/field/down.directive.js |   43 -
 .../modules/form/field/dropdown.directive.js    |   83 -
 .../js/app/modules/form/field/dropdown.jade     |   61 -
 .../main/js/app/modules/form/field/field.css    |   23 -
 .../app/modules/form/field/field.directive.js   |   44 -
 .../main/js/app/modules/form/field/field.jade   |   27 -
 .../field/form-control-feedback.directive.js    |   40 -
 .../form/field/input/autofocus.directive.js     |   30 -
 .../form/field/input/checkbox.directive.js      |   66 -
 .../app/modules/form/field/input/checkbox.jade  |   30 -
 .../form/field/input/datalist.directive.js      |  122 -
 .../app/modules/form/field/input/datalist.jade  |   51 -
 .../form/field/input/number.directive.js        |   76 -
 .../js/app/modules/form/field/input/number.jade |   50 -
 .../js/app/modules/form/field/input/text.css    |   41 -
 .../modules/form/field/input/text.directive.js  |  126 -
 .../js/app/modules/form/field/input/text.jade   |   48 -
 .../app/modules/form/field/label.directive.js   |   47 -
 .../app/modules/form/field/tooltip.directive.js |   49 -
 .../js/app/modules/form/field/up.directive.js   |   44 -
 .../src/main/js/app/modules/form/form.module.js |  101 -
 .../js/app/modules/form/group/add.directive.js  |   40 -
 .../app/modules/form/group/group.directive.js   |   81 -
 .../main/js/app/modules/form/group/group.jade   |   21 -
 .../app/modules/form/group/table.directive.js   |   29 -
 .../main/js/app/modules/form/group/table.jade   |   17 -
 .../app/modules/form/group/tooltip.directive.js |   40 -
 .../app/modules/form/panel/chevron.directive.js |   53 -
 .../app/modules/form/panel/panel.directive.js   |   37 -
 .../app/modules/form/panel/revert.directive.js  |   53 -
 .../form/validator/ipaddress.directive.js       |   86 -
 .../validator/java-built-in-class.directive.js  |   31 -
 .../form/validator/java-identifier.directive.js |   31 -
 .../form/validator/java-keywords.directive.js   |   42 -
 .../validator/java-package-name.directive.js    |   31 -
 .../java-package-specified.directive.js         |   34 -
 .../form/validator/property-unique.directive.js |   47 -
 .../property-value-specified.directive.js       |   31 -
 .../modules/form/validator/unique.directive.js  |   49 -
 .../getting-started/GettingStarted.provider.js  |  112 -
 .../src/main/js/app/modules/loading/loading.css |   73 -
 .../js/app/modules/loading/loading.directive.js |   51 -
 .../main/js/app/modules/loading/loading.jade    |   23 -
 .../js/app/modules/loading/loading.module.js    |   26 -
 .../js/app/modules/loading/loading.service.js   |   48 -
 .../js/app/modules/navbar/Navbar.provider.js    |   28 -
 .../js/app/modules/navbar/Userbar.provider.js   |   28 -
 .../js/app/modules/navbar/navbar.directive.js   |   30 -
 .../main/js/app/modules/navbar/navbar.module.js |   33 -
 .../js/app/modules/navbar/userbar.directive.js  |   48 -
 .../query-notebooks/query-notebooks.module.js   |  115 -
 .../src/main/js/app/modules/socket.module.js    |   41 -
 .../main/js/app/modules/states/admin.state.js   |   34 -
 .../app/modules/states/configuration.state.js   |  226 --
 .../caches/concurrency.directive.js             |   27 -
 .../configuration/caches/concurrency.jade       |   65 -
 .../configuration/caches/general.directive.js   |   27 -
 .../states/configuration/caches/general.jade    |   65 -
 .../configuration/caches/memory.directive.js    |   27 -
 .../states/configuration/caches/memory.jade     |   88 -
 .../configuration/caches/query.directive.js     |   27 -
 .../states/configuration/caches/query.jade      |   93 -
 .../configuration/caches/rebalance.directive.js |   27 -
 .../states/configuration/caches/rebalance.jade  |   65 -
 .../caches/server-near-cache.directive.js       |   27 -
 .../configuration/caches/server-near-cache.jade |   45 -
 .../caches/statistics.directive.js              |   27 -
 .../states/configuration/caches/statistics.jade |   37 -
 .../configuration/caches/store.directive.js     |   27 -
 .../states/configuration/caches/store.jade      |  271 --
 .../configuration/clusters/atomic.directive.js  |   27 -
 .../states/configuration/clusters/atomic.jade   |   53 -
 .../clusters/attributes.directive.js            |   27 -
 .../configuration/clusters/attributes.jade      |   58 -
 .../configuration/clusters/binary.directive.js  |   27 -
 .../states/configuration/clusters/binary.jade   |  100 -
 .../clusters/collision.directive.js             |   27 -
 .../configuration/clusters/collision.jade       |   60 -
 .../clusters/collision/custom.directive.js      |   27 -
 .../clusters/collision/custom.jade              |   24 -
 .../clusters/collision/fifo-queue.directive.js  |   27 -
 .../clusters/collision/fifo-queue.jade          |   28 -
 .../collision/job-stealing.directive.js         |   27 -
 .../clusters/collision/job-stealing.jade        |   64 -
 .../collision/priority-queue.directive.js       |   27 -
 .../clusters/collision/priority-queue.jade      |   43 -
 .../clusters/communication.directive.js         |   27 -
 .../configuration/clusters/communication.jade   |   96 -
 .../clusters/connector.directive.js             |   27 -
 .../configuration/clusters/connector.jade       |  103 -
 .../clusters/deployment.directive.js            |   27 -
 .../configuration/clusters/deployment.jade      |  119 -
 .../clusters/discovery.directive.js             |   27 -
 .../configuration/clusters/discovery.jade       |   83 -
 .../configuration/clusters/events.directive.js  |   27 -
 .../states/configuration/clusters/events.jade   |   37 -
 .../clusters/failover.directive.js              |   27 -
 .../states/configuration/clusters/failover.jade |   82 -
 .../configuration/clusters/general.directive.js |   27 -
 .../states/configuration/clusters/general.jade  |   68 -
 .../general/discovery/cloud.directive.js        |   27 -
 .../clusters/general/discovery/cloud.jade       |  127 -
 .../general/discovery/google.directive.js       |   27 -
 .../clusters/general/discovery/google.jade      |   38 -
 .../general/discovery/jdbc.directive.js         |   27 -
 .../clusters/general/discovery/jdbc.jade        |   24 -
 .../general/discovery/multicast.directive.js    |   27 -
 .../clusters/general/discovery/multicast.jade   |  109 -
 .../clusters/general/discovery/s3.directive.js  |   27 -
 .../clusters/general/discovery/s3.jade          |   27 -
 .../general/discovery/shared.directive.js       |   27 -
 .../clusters/general/discovery/shared.jade      |   23 -
 .../clusters/general/discovery/vm.directive.js  |   27 -
 .../clusters/general/discovery/vm.jade          |   90 -
 .../general/discovery/zookeeper.directive.js    |   27 -
 .../clusters/general/discovery/zookeeper.jade   |   74 -
 .../bounded-exponential-backoff.directive.js    |   27 -
 .../bounded-exponential-backoff.jade            |   27 -
 .../zookeeper/retrypolicy/custom.directive.js   |   27 -
 .../discovery/zookeeper/retrypolicy/custom.jade |   24 -
 .../exponential-backoff.directive.js            |   27 -
 .../retrypolicy/exponential-backoff.jade        |   27 -
 .../zookeeper/retrypolicy/forever.directive.js  |   27 -
 .../zookeeper/retrypolicy/forever.jade          |   22 -
 .../zookeeper/retrypolicy/n-times.directive.js  |   27 -
 .../zookeeper/retrypolicy/n-times.jade          |   25 -
 .../zookeeper/retrypolicy/one-time.directive.js |   27 -
 .../zookeeper/retrypolicy/one-time.jade         |   23 -
 .../retrypolicy/until-elapsed.directive.js      |   27 -
 .../zookeeper/retrypolicy/until-elapsed.jade    |   25 -
 .../configuration/clusters/igfs.directive.js    |   27 -
 .../states/configuration/clusters/igfs.jade     |   37 -
 .../configuration/clusters/logger.directive.js  |   27 -
 .../states/configuration/clusters/logger.jade   |   65 -
 .../clusters/logger/custom.directive.js         |   27 -
 .../configuration/clusters/logger/custom.jade   |   24 -
 .../clusters/logger/log4j.directive.js          |   27 -
 .../configuration/clusters/logger/log4j.jade    |   49 -
 .../clusters/logger/log4j2.directive.js         |   27 -
 .../configuration/clusters/logger/log4j2.jade   |   38 -
 .../clusters/marshaller.directive.js            |   27 -
 .../configuration/clusters/marshaller.jade      |   69 -
 .../configuration/clusters/metrics.directive.js |   27 -
 .../states/configuration/clusters/metrics.jade  |   50 -
 .../configuration/clusters/ssl.directive.js     |   27 -
 .../states/configuration/clusters/ssl.jade      |  108 -
 .../configuration/clusters/swap.directive.js    |   27 -
 .../states/configuration/clusters/swap.jade     |   67 -
 .../configuration/clusters/thread.directive.js  |   27 -
 .../states/configuration/clusters/thread.jade   |   48 -
 .../configuration/clusters/time.directive.js    |   27 -
 .../states/configuration/clusters/time.jade     |   47 -
 .../clusters/transactions.directive.js          |   27 -
 .../configuration/clusters/transactions.jade    |   59 -
 .../configuration/domains/general.directive.js  |   27 -
 .../states/configuration/domains/general.jade   |   46 -
 .../configuration/domains/query.directive.js    |   27 -
 .../states/configuration/domains/query.jade     |  169 -
 .../configuration/domains/store.directive.js    |   27 -
 .../states/configuration/domains/store.jade     |  126 -
 .../states/configuration/igfs/dual.directive.js |   27 -
 .../modules/states/configuration/igfs/dual.jade |   42 -
 .../igfs/fragmentizer.directive.js              |   27 -
 .../states/configuration/igfs/fragmentizer.jade |   43 -
 .../configuration/igfs/general.directive.js     |   27 -
 .../states/configuration/igfs/general.jade      |   53 -
 .../states/configuration/igfs/ipc.directive.js  |   27 -
 .../modules/states/configuration/igfs/ipc.jade  |   57 -
 .../states/configuration/igfs/misc.directive.js |   27 -
 .../modules/states/configuration/igfs/misc.jade |  108 -
 .../configuration/igfs/secondary.directive.js   |   27 -
 .../states/configuration/igfs/secondary.jade    |   44 -
 .../configuration/preview-panel.directive.js    |  239 --
 .../summary/summary-tabs.directive.js           |   50 -
 .../configuration/summary/summary.controller.js |  359 --
 .../configuration/summary/summary.resource.js   |   40 -
 .../main/js/app/modules/states/logout.state.js  |   36 -
 .../js/app/modules/states/password.state.js     |   46 -
 .../main/js/app/modules/states/profile.state.js |   34 -
 .../main/js/app/modules/states/signin.state.js  |   53 -
 .../src/main/js/app/modules/states/sql.state.js |   46 -
 .../main/js/app/modules/user/Auth.service.js    |   76 -
 .../main/js/app/modules/user/User.service.js    |   65 -
 .../src/main/js/app/modules/user/user.module.js |   28 -
 .../main/js/app/services/ChartColors.service.js |   22 -
 .../src/main/js/app/services/Clone.service.js   |   64 -
 .../src/main/js/app/services/Confirm.service.js |   70 -
 .../js/app/services/ConfirmBatch.service.js     |   92 -
 .../js/app/services/CopyToClipboard.service.js  |   50 -
 .../main/js/app/services/Countries.service.js   |   31 -
 .../src/main/js/app/services/Focus.service.js   |   33 -
 .../main/js/app/services/InetAddress.service.js |   53 -
 .../main/js/app/services/JavaTypes.service.js   |   84 -
 .../main/js/app/services/LegacyTable.service.js |  205 -
 .../main/js/app/services/LegacyUtils.service.js |  948 -----
 .../main/js/app/services/Messages.service.js    |   63 -
 .../js/app/services/ModelNormalizer.service.js  |   59 -
 .../app/services/UnsavedChangesGuard.service.js |   38 -
 modules/web-console/src/main/js/app/vendor.js   |   54 -
 .../src/main/js/controllers/admin-controller.js |   91 -
 .../main/js/controllers/caches-controller.js    |  470 ---
 .../main/js/controllers/clusters-controller.js  |  626 ----
 .../main/js/controllers/domains-controller.js   | 1746 ---------
 .../src/main/js/controllers/igfs-controller.js  |  401 --
 .../main/js/controllers/profile-controller.js   |   91 -
 .../src/main/js/controllers/sql-controller.js   | 1588 --------
 .../src/main/js/generator/generator-common.js   |  611 ---
 .../src/main/js/generator/generator-java.js     | 3404 -----------------
 .../src/main/js/generator/generator-optional.js |   25 -
 .../main/js/generator/generator-properties.js   |  150 -
 .../src/main/js/generator/generator-readme.js   |   85 -
 .../src/main/js/generator/generator-xml.js      | 1978 ----------
 .../src/main/js/gulpfile.babel.js/index.js      |   26 -
 .../src/main/js/gulpfile.babel.js/paths.js      |   70 -
 .../main/js/gulpfile.babel.js/tasks/build.js    |   21 -
 .../main/js/gulpfile.babel.js/tasks/bundle.js   |   32 -
 .../main/js/gulpfile.babel.js/tasks/clean.js    |   32 -
 .../src/main/js/gulpfile.babel.js/tasks/copy.js |   33 -
 .../gulpfile.babel.js/tasks/ignite-modules.js   |   55 -
 .../src/main/js/gulpfile.babel.js/tasks/jade.js |   40 -
 .../main/js/gulpfile.babel.js/tasks/watch.js    |   31 -
 .../main/js/gulpfile.babel.js/webpack/common.js |  192 -
 .../webpack/environments/development.js         |   64 -
 .../webpack/environments/production.js          |   45 -
 .../main/js/gulpfile.babel.js/webpack/index.js  |   32 -
 .../webpack/plugins/progress.js                 |   82 -
 .../src/main/js/ignite_modules/README.txt       |    6 -
 .../src/main/js/ignite_modules/index.js         |   27 -
 modules/web-console/src/main/js/package.json    |  128 -
 .../web-console/src/main/js/public/favicon.ico  |  Bin 1150 -> 0 bytes
 .../src/main/js/public/images/cache.png         |  Bin 23700 -> 0 bytes
 .../src/main/js/public/images/cluster.png       |  Bin 29376 -> 0 bytes
 .../src/main/js/public/images/docker.png        |  Bin 521 -> 0 bytes
 .../src/main/js/public/images/domains.png       |  Bin 23828 -> 0 bytes
 .../src/main/js/public/images/igfs.png          |  Bin 14307 -> 0 bytes
 .../src/main/js/public/images/ignite-logo.png   |  Bin 1982 -> 0 bytes
 .../main/js/public/images/ignite-logo@2x.png    |  Bin 3325 -> 0 bytes
 .../src/main/js/public/images/ignite-puzzle.png |  Bin 71974 -> 0 bytes
 .../src/main/js/public/images/java.png          |  Bin 170 -> 0 bytes
 .../src/main/js/public/images/pb-ignite.png     |  Bin 3493 -> 0 bytes
 .../src/main/js/public/images/pb-ignite@2x.png  |  Bin 8558 -> 0 bytes
 .../src/main/js/public/images/query-chart.png   |  Bin 16637 -> 0 bytes
 .../main/js/public/images/query-metadata.png    |  Bin 32298 -> 0 bytes
 .../src/main/js/public/images/query-table.png   |  Bin 29189 -> 0 bytes
 .../src/main/js/public/images/summary.png       |  Bin 31997 -> 0 bytes
 .../src/main/js/public/images/xml.png           |  Bin 232 -> 0 bytes
 .../public/stylesheets/_bootstrap-custom.scss   |   65 -
 .../stylesheets/_bootstrap-variables.scss       |  891 -----
 .../stylesheets/_font-awesome-custom.scss       |   32 -
 .../src/main/js/public/stylesheets/style.scss   | 2156 -----------
 .../main/js/public/stylesheets/variables.scss   |   28 -
 modules/web-console/src/main/js/serve.js        |  116 -
 modules/web-console/src/main/js/serve/agent.js  |  714 ----
 .../src/main/js/serve/agent_dists/README.txt    |    7 -
 modules/web-console/src/main/js/serve/app.js    |   42 -
 .../web-console/src/main/js/serve/browser.js    |  378 --
 .../main/js/serve/config/settings.json.sample   |   26 -
 .../web-console/src/main/js/serve/configure.js  |   84 -
 modules/web-console/src/main/js/serve/mail.js   |   75 -
 modules/web-console/src/main/js/serve/mongo.js  |  676 ----
 .../src/main/js/serve/routes/admin.js           |  126 -
 .../src/main/js/serve/routes/agent.js           |   81 -
 .../src/main/js/serve/routes/caches.js          |  132 -
 .../src/main/js/serve/routes/clusters.js        |  146 -
 .../src/main/js/serve/routes/demo.js            |  135 -
 .../src/main/js/serve/routes/demo/caches.json   |   87 -
 .../src/main/js/serve/routes/demo/clusters.json |   50 -
 .../src/main/js/serve/routes/demo/domains.json  |  307 --
 .../src/main/js/serve/routes/demo/igfss.json    |   10 -
 .../src/main/js/serve/routes/domains.js         |  195 -
 .../src/main/js/serve/routes/igfs.js            |  122 -
 .../src/main/js/serve/routes/notebooks.js       |  121 -
 .../src/main/js/serve/routes/profile.js         |  102 -
 .../src/main/js/serve/routes/public.js          |  235 --
 .../src/main/js/serve/routes/routes.js          |  103 -
 .../web-console/src/main/js/serve/settings.js   |   84 -
 modules/web-console/src/main/js/views/base.jade |   22 -
 .../src/main/js/views/configuration/caches.jade |   52 -
 .../main/js/views/configuration/clusters.jade   |   64 -
 .../js/views/configuration/domains-import.jade  |  211 --
 .../main/js/views/configuration/domains.jade    |   66 -
 .../src/main/js/views/configuration/igfs.jade   |   51 -
 .../main/js/views/configuration/sidebar.jade    |   29 -
 .../summary-project-structure.jade              |   27 -
 .../js/views/configuration/summary-tabs.jade    |   25 -
 .../main/js/views/configuration/summary.jade    |  152 -
 .../src/main/js/views/includes/footer.jade      |   23 -
 .../src/main/js/views/includes/header.jade      |   51 -
 .../web-console/src/main/js/views/index.jade    |   48 -
 .../web-console/src/main/js/views/reset.jade    |   48 -
 .../src/main/js/views/settings/admin.jade       |   76 -
 .../src/main/js/views/settings/profile.jade     |   76 -
 .../web-console/src/main/js/views/signin.jade   |  163 -
 .../src/main/js/views/sql/cache-metadata.jade   |   40 -
 .../src/main/js/views/sql/chart-settings.jade   |   40 -
 .../src/main/js/views/sql/notebook-new.jade     |   31 -
 .../src/main/js/views/sql/paragraph-rate.jade   |   31 -
 .../web-console/src/main/js/views/sql/sql.jade  |  201 -
 .../main/js/views/templates/agent-download.jade |   48 -
 .../src/main/js/views/templates/alert.jade      |   21 -
 .../main/js/views/templates/batch-confirm.jade  |   32 -
 .../src/main/js/views/templates/clone.jade      |   31 -
 .../src/main/js/views/templates/confirm.jade    |   31 -
 .../src/main/js/views/templates/demo-info.jade  |   45 -
 .../src/main/js/views/templates/dropdown.jade   |   21 -
 .../js/views/templates/getting-started.jade     |   32 -
 .../src/main/js/views/templates/message.jade    |   26 -
 .../src/main/js/views/templates/pagination.jade |   32 -
 .../src/main/js/views/templates/select.jade     |   26 -
 .../js/views/templates/validation-error.jade    |   25 -
 modules/web-console/src/test/js/routes/agent.js |   94 -
 modules/web-console/web-agent/.gitignore        |    2 +
 modules/web-console/web-agent/README.txt        |   88 +
 .../web-agent/assembly/release-web-agent.xml    |   66 +
 .../web-agent/bin/ignite-web-agent.bat          |   70 +
 .../web-agent/bin/ignite-web-agent.sh           |   87 +
 modules/web-console/web-agent/demo/README.txt   |    4 +
 modules/web-console/web-agent/demo/db-init.sql  |  102 +
 .../web-agent/jdbc-drivers/README.txt           |   10 +
 modules/web-console/web-agent/logs/README.txt   |    5 +
 modules/web-console/web-agent/pom.xml           |  199 +
 .../console/agent/AgentConfiguration.java       |  268 ++
 .../ignite/console/agent/AgentLauncher.java     |  344 ++
 .../apache/ignite/console/agent/AgentUtils.java |  111 +
 .../console/agent/handlers/AbstractHandler.java |  110 +
 .../console/agent/handlers/DatabaseHandler.java |  298 ++
 .../console/agent/handlers/RestHandler.java     |  276 ++
 .../ignite/console/demo/AgentClusterDemo.java   |  641 ++++
 .../ignite/console/demo/AgentMetadataDemo.java  |   92 +
 .../apache/ignite/console/demo/model/Car.java   |  152 +
 .../ignite/console/demo/model/Country.java      |  152 +
 .../ignite/console/demo/model/Department.java   |  152 +
 .../ignite/console/demo/model/Employee.java     |  356 ++
 .../ignite/console/demo/model/Parking.java      |  152 +
 .../src/main/resources/log4j.properties         |   53 +
 pom.xml                                         |    2 +-
 861 files changed, 45009 insertions(+), 41666 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/core/src/main/java/org/apache/ignite/internal/visor/event/VisorGridDiscoveryEventV2.java
----------------------------------------------------------------------
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/visor/event/VisorGridDiscoveryEventV2.java b/modules/core/src/main/java/org/apache/ignite/internal/visor/event/VisorGridDiscoveryEventV2.java
new file mode 100644
index 0000000..b66aacf
--- /dev/null
+++ b/modules/core/src/main/java/org/apache/ignite/internal/visor/event/VisorGridDiscoveryEventV2.java
@@ -0,0 +1,80 @@
+/*
+ * 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.
+ */
+
+package org.apache.ignite.internal.visor.event;
+
+import java.util.UUID;
+import org.apache.ignite.internal.util.typedef.internal.S;
+import org.apache.ignite.lang.IgniteUuid;
+import org.jetbrains.annotations.Nullable;
+
+/**
+ * Lightweight counterpart for {@link org.apache.ignite.events.DiscoveryEvent}.
+ */
+public class VisorGridDiscoveryEventV2 extends VisorGridDiscoveryEvent {
+    /** */
+    private static final long serialVersionUID = 0L;
+
+    /** Topology version. */
+    private final long topVer;
+
+    /**
+     * Create event with given parameters.
+     *
+     * @param typeId Event type.
+     * @param id Event id.
+     * @param name Event name.
+     * @param nid Event node ID.
+     * @param ts Event timestamp.
+     * @param msg Event message.
+     * @param shortDisplay Shortened version of {@code toString()} result.
+     * @param evtNodeId Event node id.
+     * @param addr Event node address.
+     * @param isDaemon If event node is daemon on not.
+     * @param topVer Topology version.
+     */
+    public VisorGridDiscoveryEventV2(
+        int typeId,
+        IgniteUuid id,
+        String name,
+        UUID nid,
+        long ts,
+        @Nullable String msg,
+        String shortDisplay,
+        UUID evtNodeId,
+        String addr,
+        boolean isDaemon,
+        long topVer
+    ) {
+        super(typeId, id, name, nid, ts, msg, shortDisplay, evtNodeId, addr, isDaemon);
+
+        this.topVer = topVer;
+    }
+
+    /**
+     * @return Topology version or {@code 0} if configured discovery SPI implementation
+     *      does not support versioning.
+     **/
+    public long topologyVersion() {
+        return topVer;
+    }
+
+    /** {@inheritDoc} */
+    @Override public String toString() {
+        return S.toString(VisorGridDiscoveryEventV2.class, this);
+    }
+}

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/core/src/main/java/org/apache/ignite/internal/visor/node/VisorNodeDataCollectorJob.java
----------------------------------------------------------------------
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/visor/node/VisorNodeDataCollectorJob.java b/modules/core/src/main/java/org/apache/ignite/internal/visor/node/VisorNodeDataCollectorJob.java
index 611dcde..abe1364 100644
--- a/modules/core/src/main/java/org/apache/ignite/internal/visor/node/VisorNodeDataCollectorJob.java
+++ b/modules/core/src/main/java/org/apache/ignite/internal/visor/node/VisorNodeDataCollectorJob.java
@@ -41,6 +41,8 @@ import org.apache.ignite.lang.IgniteProductVersion;
 import static org.apache.ignite.internal.processors.cache.GridCacheUtils.isIgfsCache;
 import static org.apache.ignite.internal.processors.cache.GridCacheUtils.isSystemCache;
 import static org.apache.ignite.internal.visor.compute.VisorComputeMonitoringHolder.COMPUTE_MONITORING_HOLDER_KEY;
+import static org.apache.ignite.internal.visor.util.VisorTaskUtils.EVT_MAPPER;
+import static org.apache.ignite.internal.visor.util.VisorTaskUtils.EVT_MAPPER_V2;
 import static org.apache.ignite.internal.visor.util.VisorTaskUtils.VISOR_TASK_EVTS;
 import static org.apache.ignite.internal.visor.util.VisorTaskUtils.checkExplicitTaskMonitoring;
 import static org.apache.ignite.internal.visor.util.VisorTaskUtils.collectEvents;
@@ -62,6 +64,9 @@ public class VisorNodeDataCollectorJob extends VisorJob<VisorNodeDataCollectorTa
     /** */
     private static final IgniteProductVersion VER_1_5_26 = IgniteProductVersion.fromString("1.5.26");
 
+    /** */
+    protected static final IgniteProductVersion VER_1_7_2 = IgniteProductVersion.fromString("1.7.2");
+
     /**
      * Create job with given argument.
      *
@@ -82,7 +87,8 @@ public class VisorNodeDataCollectorJob extends VisorJob<VisorNodeDataCollectorTa
      */
     protected void events0(VisorNodeDataCollectorJobResult res, String evtOrderKey, String evtThrottleCntrKey,
         final boolean all) {
-        res.events().addAll(collectEvents(ignite, evtOrderKey, evtThrottleCntrKey, all));
+        res.events().addAll(collectEvents(ignite, evtOrderKey, evtThrottleCntrKey, all,
+            compatibleWith(VER_1_7_2) ? EVT_MAPPER_V2 : EVT_MAPPER));
     }
 
     /**
@@ -132,7 +138,7 @@ public class VisorNodeDataCollectorJob extends VisorJob<VisorNodeDataCollectorTa
      * @param ver Version to check.
      * @return {@code true} if found at least one compatible node with specified version.
      */
-    private boolean compatibleWith(IgniteProductVersion ver) {
+    protected boolean compatibleWith(IgniteProductVersion ver) {
         for (ClusterNode node : ignite.cluster().nodes())
             if (node.version().compareToIgnoreTimestamp(ver) <= 0)
                 return true;

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/core/src/main/java/org/apache/ignite/internal/visor/util/VisorEventMapper.java
----------------------------------------------------------------------
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/visor/util/VisorEventMapper.java b/modules/core/src/main/java/org/apache/ignite/internal/visor/util/VisorEventMapper.java
index 7e3ae96..829adb3 100644
--- a/modules/core/src/main/java/org/apache/ignite/internal/visor/util/VisorEventMapper.java
+++ b/modules/core/src/main/java/org/apache/ignite/internal/visor/util/VisorEventMapper.java
@@ -55,38 +55,88 @@ public class VisorEventMapper implements IgniteClosure<Event, VisorGridEvent> {
      */
     protected VisorGridEvent map(Event evt, int type, IgniteUuid id, String name, UUID nid, long ts, String msg,
         String shortDisplay) {
-        if (evt instanceof TaskEvent) {
-            TaskEvent te = (TaskEvent)evt;
+        if (evt instanceof TaskEvent)
+            return taskEvent((TaskEvent)evt, type, id, name, nid, ts, msg, shortDisplay);
 
-            return new VisorGridTaskEvent(type, id, name, nid, ts, msg, shortDisplay,
-                te.taskName(), te.taskClassName(), te.taskSessionId(), te.internal());
-        }
+        if (evt instanceof JobEvent)
+            return jobEvent((JobEvent)evt, type, id, name, nid, ts, msg, shortDisplay);
 
-        if (evt instanceof JobEvent) {
-            JobEvent je = (JobEvent)evt;
+        if (evt instanceof DeploymentEvent)
+            return deploymentEvent((DeploymentEvent)evt, type, id, name, nid, ts, msg, shortDisplay);
 
-            return new VisorGridJobEvent(type, id, name, nid, ts, msg, shortDisplay,
-                je.taskName(), je.taskClassName(), je.taskSessionId(), je.jobId());
-        }
+        if (evt instanceof DiscoveryEvent)
+            return discoveryEvent((DiscoveryEvent)evt, type, id, name, nid, ts, msg, shortDisplay);
 
-        if (evt instanceof DeploymentEvent) {
-            DeploymentEvent de = (DeploymentEvent)evt;
-
-            return new VisorGridDeploymentEvent(type, id, name, nid, ts, msg, shortDisplay, de.alias());
-        }
+        return null;
+    }
 
-        if (evt instanceof DiscoveryEvent) {
-            DiscoveryEvent de = (DiscoveryEvent)evt;
+    /**
+     * @param te Task event.
+     * @param type Event's type.
+     * @param id Event id.
+     * @param name Event name.
+     * @param nid Event node ID.
+     * @param ts Event timestamp.
+     * @param msg Event message.
+     * @param shortDisplay Shortened version of {@code toString()} result.
+     * @return Visor data transfer object for event.
+     */
+    protected VisorGridEvent taskEvent(TaskEvent te, int type, IgniteUuid id, String name, UUID nid, long ts,
+        String msg, String shortDisplay) {
+        return new VisorGridTaskEvent(type, id, name, nid, ts, msg, shortDisplay,
+            te.taskName(), te.taskClassName(), te.taskSessionId(), te.internal());
+    }
 
-            ClusterNode node = de.eventNode();
+    /**
+     * @param je Job event.
+     * @param type Event's type.
+     * @param id Event id.
+     * @param name Event name.
+     * @param nid Event node ID.
+     * @param ts Event timestamp.
+     * @param msg Event message.
+     * @param shortDisplay Shortened version of {@code toString()} result.
+     * @return Visor data transfer object for event.
+     */
+    protected VisorGridEvent jobEvent(JobEvent je, int type, IgniteUuid id, String name, UUID nid, long ts,
+        String msg, String shortDisplay) {
+        return new VisorGridJobEvent(type, id, name, nid, ts, msg, shortDisplay, je.taskName(), je.taskClassName(),
+            je.taskSessionId(), je.jobId());
+    }
 
-            String addr = F.first(node.addresses());
+    /**
+     * @param de Deployment event.
+     * @param type Event's type.
+     * @param id Event id.
+     * @param name Event name.
+     * @param nid Event node ID.
+     * @param ts Event timestamp.
+     * @param msg Event message.
+     * @param shortDisplay Shortened version of {@code toString()} result.
+     * @return Visor data transfer object for event.
+     */
+    protected VisorGridEvent deploymentEvent(DeploymentEvent de, int type, IgniteUuid id, String name, UUID nid,
+        long ts, String msg, String shortDisplay) {
+        return new VisorGridDeploymentEvent(type, id, name, nid, ts, msg, shortDisplay, de.alias());
+    }
 
-            return new VisorGridDiscoveryEvent(type, id, name, nid, ts, msg, shortDisplay,
-                node.id(), addr, node.isDaemon());
-        }
+    /**
+     * @param de Discovery event.
+     * @param type Event's type.
+     * @param id Event id.
+     * @param name Event name.
+     * @param nid Event node ID.
+     * @param ts Event timestamp.
+     * @param msg Event message.
+     * @param shortDisplay Shortened version of {@code toString()} result.
+     * @return Visor data transfer object for event.
+     */
+    protected VisorGridEvent discoveryEvent(DiscoveryEvent de, int type, IgniteUuid id, String name, UUID nid,
+        long ts, String msg, String shortDisplay) {
+        ClusterNode node = de.eventNode();
 
-        return null;
+        return new VisorGridDiscoveryEvent(type, id, name, nid, ts, msg, shortDisplay, node.id(),
+            F.first(node.addresses()), node.isDaemon());
     }
 
     /** {@inheritDoc} */

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/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 2721be4..25aaab5 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
@@ -41,6 +41,7 @@ import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
 import java.util.SortedMap;
+import java.util.UUID;
 import java.util.concurrent.ConcurrentMap;
 import java.util.concurrent.atomic.AtomicBoolean;
 import java.util.zip.ZipEntry;
@@ -54,18 +55,21 @@ import org.apache.ignite.cache.eviction.fifo.FifoEvictionPolicyMBean;
 import org.apache.ignite.cache.eviction.lru.LruEvictionPolicyMBean;
 import org.apache.ignite.cache.eviction.random.RandomEvictionPolicyMBean;
 import org.apache.ignite.cluster.ClusterNode;
+import org.apache.ignite.events.DiscoveryEvent;
 import org.apache.ignite.events.Event;
 import org.apache.ignite.internal.processors.igfs.IgfsEx;
 import org.apache.ignite.internal.util.typedef.F;
 import org.apache.ignite.internal.util.typedef.X;
 import org.apache.ignite.internal.util.typedef.internal.SB;
 import org.apache.ignite.internal.util.typedef.internal.U;
+import org.apache.ignite.internal.visor.event.VisorGridDiscoveryEventV2;
 import org.apache.ignite.internal.visor.event.VisorGridEvent;
 import org.apache.ignite.internal.visor.event.VisorGridEventsLost;
 import org.apache.ignite.internal.visor.file.VisorFileBlock;
 import org.apache.ignite.internal.visor.log.VisorLogFile;
 import org.apache.ignite.lang.IgniteClosure;
 import org.apache.ignite.lang.IgnitePredicate;
+import org.apache.ignite.lang.IgniteUuid;
 import org.jetbrains.annotations.Nullable;
 
 import static java.lang.System.getProperty;
@@ -382,6 +386,17 @@ public class VisorTaskUtils {
     /** Mapper from grid event to Visor data transfer object. */
     public static final VisorEventMapper EVT_MAPPER = new VisorEventMapper();
 
+    /** Mapper from grid event to Visor data transfer object. */
+    public static final VisorEventMapper EVT_MAPPER_V2 = new VisorEventMapper() {
+        @Override protected VisorGridEvent discoveryEvent(DiscoveryEvent de, int type, IgniteUuid id, String name,
+            UUID nid, long ts, String msg, String shortDisplay) {
+            ClusterNode node = de.eventNode();
+
+            return new VisorGridDiscoveryEventV2(type, id, name, nid, ts, msg, shortDisplay, node.id(),
+                F.first(node.addresses()), node.isDaemon(), de.topologyVersion());
+        }
+    };
+
     /**
      * Grabs local events and detects if events was lost since last poll.
      *
@@ -389,17 +404,18 @@ public class VisorTaskUtils {
      * @param evtOrderKey Unique key to take last order key from node local map.
      * @param evtThrottleCntrKey Unique key to take throttle count from node local map.
      * @param all If {@code true} then collect all events otherwise collect only non task events.
+     * @param evtMapper Closure to map grid events to Visor data transfer objects.
      * @return Collections of node events
      */
     public static Collection<VisorGridEvent> collectEvents(Ignite ignite, String evtOrderKey, String evtThrottleCntrKey,
-        final boolean all) {
+        boolean all, IgniteClosure<Event, VisorGridEvent> evtMapper) {
         int[] evtTypes = all ? VISOR_ALL_EVTS : VISOR_NON_TASK_EVTS;
 
         // Collect discovery events for Web Console.
         if (evtOrderKey.startsWith("CONSOLE_"))
             evtTypes = concat(evtTypes, EVTS_DISCOVERY);
 
-        return collectEvents(ignite, evtOrderKey, evtThrottleCntrKey, evtTypes, EVT_MAPPER);
+        return collectEvents(ignite, evtOrderKey, evtThrottleCntrKey, evtTypes, evtMapper);
     }
 
     /**
@@ -413,7 +429,7 @@ public class VisorTaskUtils {
      * @return Collections of node events
      */
     public static Collection<VisorGridEvent> collectEvents(Ignite ignite, String evtOrderKey, String evtThrottleCntrKey,
-        final int[] evtTypes, IgniteClosure<Event, VisorGridEvent> evtMapper) {
+        int[] evtTypes, IgniteClosure<Event, VisorGridEvent> evtMapper) {
         assert ignite != null;
         assert evtTypes != null && evtTypes.length > 0;
 

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-agent/.gitignore
----------------------------------------------------------------------
diff --git a/modules/web-agent/.gitignore b/modules/web-agent/.gitignore
deleted file mode 100644
index 57dd45e..0000000
--- a/modules/web-agent/.gitignore
+++ /dev/null
@@ -1,2 +0,0 @@
-logs/*.log.*
-jdbc-drivers/*.jar

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-agent/README.txt
----------------------------------------------------------------------
diff --git a/modules/web-agent/README.txt b/modules/web-agent/README.txt
deleted file mode 100644
index c6e625b..0000000
--- a/modules/web-agent/README.txt
+++ /dev/null
@@ -1,88 +0,0 @@
-Ignite Web Agent
-======================================
-Ignite Web Agent is a java standalone application that allow to connect Ignite Grid to Ignite Web Console.
-Ignite Web Agent communicates with grid nodes via REST interface and connects to Ignite Web Console via web-socket.
-
-Two main functions of Ignite Web Agent:
- 1. Proxy between Ignite Web Console and Ignite Grid to execute SQL statements and collect metrics for monitoring.
-   You may need to specify URI for connect to Ignite REST server via "-n" option.
-
- 2. Proxy between Ignite Web Console and user RDBMS to collect database metadata for later CacheTypeMetadata configuration.
-   You may need to copy JDBC driver into "./jdbc-drivers" subfolder or specify path via "-d" option.
-
-Usage example:
-  ignite-web-agent.sh
-
-Configuration file:
-  Should be a file with simple line-oriented format as described here: http://docs.oracle.com/javase/7/docs/api/java/util/Properties.html#load(java.io.Reader)
-
-  Available entries names:
-    tokens
-    server-uri
-    node-uri
-    driver-folder
-
-  Example configuration file:
-    tokens=1a2b3c4d5f,2j1s134d12
-    serverURI=https://console.example.com:3001
-
-Security tokens:
-  1) By default security token of current user will be included into "default.properties" inside downloaded "ignite-web-agent-x.x.x.zip".
-  2) One can get/reset token in Web Console profile (https://<your_console_address>/settings/profile).
-  3) One may specify several comma separated tokens using configuration file or command line arguments of web agent.
-
-Ignite Web agent requirements:
-  1) In order to communicate with web agent Ignite node should be started with REST server (move ignite-rest-http folder from lib/optional/ to lib/).
-  2) Configure web agent serverURI property by Ignite node REST server URI.
-
-Options:
-  -h, --help
-     Print this help message
-  -c, --config
-     Path to configuration file
-  -d, --driver-folder
-     Path to folder with JDBC drivers, default value: ./jdbc-drivers
-  -n, --node-uri
-     URI for connect to Ignite REST server, default value:
-     http://localhost:8080
-  -s, --server-uri
-     URI for connect to Ignite Web Console via web-socket protocol, default
-     value: http://localhost:3001
-  -t, --tokens
-     User's security tokens
-
-How to build:
-  To build from sources run following command in Ignite project root folder:
-  mvn clean package -pl :ignite-web-agent -am -P web-console -DskipTests=true
-
-Demo of Ignite Web Agent:
- In order to simplify evaluation demo mode was implemented. To start demo, you need to click button "Start demo".
- New tab will be open with prepared demo data.
-
- 1) Demo for import domain model from database.
-   In this mode an in-memory H2 database will be started.
-   How to evaluate:
-     1.1) Go to Ignite Web Console "Domain model" screen.
-     1.2) Click "Import from database". You should see modal with demo description.
-     1.3) Click "Next" button. You should see list of available schemas.
-     1.4) Click "Next" button. You should see list of available tables.
-     1.5) Click "Next" button. You should see import options.
-     1.6) Select some of them and click "Save".
-
-   2) Demo for SQL.
-     How to evaluate:
-     In this mode internal Ignite node will be started. Cache created and populated with data.
-       2.1) Click "SQL" in Ignite Web Console top menu.
-       2.2) "Demo" notebook with preconfigured queries will be opened.
-       2.3) You can also execute any SQL queries for tables: "Country, Department, Employee, Parking, Car".
-
- For example:
-   2.4) Enter SQL statement:
-           SELECT p.name, count(*) AS cnt
-           FROM "ParkingCache".Parking p
-           INNER JOIN "CarCache".Car c
-             ON (p.id) = (c.parkingId)
-           GROUP BY P.NAME
-   2.5) Click "Execute" button. You should get some data in table.
-   2.6) Click charts buttons to see auto generated charts.
-

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-agent/assembly/release-web-agent.xml
----------------------------------------------------------------------
diff --git a/modules/web-agent/assembly/release-web-agent.xml b/modules/web-agent/assembly/release-web-agent.xml
deleted file mode 100644
index aa85b59..0000000
--- a/modules/web-agent/assembly/release-web-agent.xml
+++ /dev/null
@@ -1,72 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-
-<!--
-  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.
--->
-
-<assembly xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
-          xmlns="http://maven.apache.org/plugins/maven-assembly-plugin/assembly/1.1.3"
-          xsi:schemaLocation="http://maven.apache.org/plugins/maven-assembly-plugin/assembly/1.1.3 http://maven.apache.org/xsd/assembly-1.1.3.xsd">
-    <id>release-ignite-web-agent</id>
-
-    <formats>
-        <format>zip</format>
-    </formats>
-
-    <fileSets>
-        <fileSet>
-            <directory>${basedir}</directory>
-            <outputDirectory>/</outputDirectory>
-            <includes>
-                <include>jdbc-drivers/README*</include>
-                <include>demo/README*</include>
-                <include>demo/*.sql</include>
-                <include>README*</include>
-                <include>LICENSE*</include>
-                <include>NOTICE*</include>
-            </includes>
-        </fileSet>
-        <fileSet>
-            <directory>${basedir}/bin</directory>
-            <outputDirectory>/</outputDirectory>
-            <includes>
-                <include>**/*.bat</include>
-            </includes>
-        </fileSet>
-        <fileSet>
-            <directory>${basedir}/bin</directory>
-            <outputDirectory>/</outputDirectory>
-            <fileMode>0755</fileMode>
-            <includes>
-                <include>**/*.sh</include>
-            </includes>
-        </fileSet>
-        <fileSet>
-            <directory>${basedir}/logs</directory>
-            <outputDirectory>/logs</outputDirectory>
-            <includes>
-                <include>README*</include>
-            </includes>
-        </fileSet>
-        <fileSet>
-            <directory>${project.build.directory}</directory>
-            <outputDirectory>/</outputDirectory>
-            <includes>
-                <include>ignite-web-agent-${project.version}.jar</include>
-            </includes>
-        </fileSet>
-    </fileSets>
-</assembly>

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-agent/bin/ignite-web-agent.bat
----------------------------------------------------------------------
diff --git a/modules/web-agent/bin/ignite-web-agent.bat b/modules/web-agent/bin/ignite-web-agent.bat
deleted file mode 100644
index f16eb35..0000000
--- a/modules/web-agent/bin/ignite-web-agent.bat
+++ /dev/null
@@ -1,70 +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.
-::
-
-@echo off
-Setlocal EnableDelayedExpansion
-
-if "%OS%" == "Windows_NT"  setlocal
-
-:: Check JAVA_HOME.
-if defined JAVA_HOME  goto checkJdk
-    echo %0, ERROR:
-    echo JAVA_HOME environment variable is not found.
-    echo Please point JAVA_HOME variable to location of JDK 1.7 or JDK 1.8.
-    echo You can also download latest JDK at http://java.com/download.
-goto error_finish
-
-:checkJdk
-:: Check that JDK is where it should be.
-if exist "%JAVA_HOME%\bin\java.exe" goto checkJdkVersion
-    echo %0, ERROR:
-    echo JAVA is not found in JAVA_HOME=%JAVA_HOME%.
-    echo Please point JAVA_HOME variable to installation of JDK 1.7 or JDK 1.8.
-    echo You can also download latest JDK at http://java.com/download.
-goto error_finish
-
-:checkJdkVersion
-"%JAVA_HOME%\bin\java.exe" -version 2>&1 | findstr "1\.[78]\." > nul
-if %ERRORLEVEL% equ 0 goto run_java
-    echo %0, ERROR:
-    echo The version of JAVA installed in %JAVA_HOME% is incorrect.
-    echo Please point JAVA_HOME variable to installation of JDK 1.7 or JDK 1.8.
-    echo You can also download latest JDK at http://java.com/download.
-goto error_finish
-
-:run_java
-
-::
-:: JVM options. See http://java.sun.com/javase/technologies/hotspot/vmoptions.jsp for more details.
-::
-:: ADD YOUR/CHANGE ADDITIONAL OPTIONS HERE
-::
-if "%JVM_OPTS%" == "" set JVM_OPTS=-Xms1g -Xmx1g -server -XX:+AggressiveOpts -XX:MaxPermSize=256m
-
-"%JAVA_HOME%\bin\java.exe" %JVM_OPTS% -cp "*" org.apache.ignite.console.agent.AgentLauncher  %*
-
-set JAVA_ERRORLEVEL=%ERRORLEVEL%
-
-:: errorlevel 130 if aborted with Ctrl+c
-if %JAVA_ERRORLEVEL%==130 goto eof
-
-:error_finish
-
-if not "%NO_PAUSE%" == "1" pause
-
-goto :eof
-

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-agent/bin/ignite-web-agent.sh
----------------------------------------------------------------------
diff --git a/modules/web-agent/bin/ignite-web-agent.sh b/modules/web-agent/bin/ignite-web-agent.sh
deleted file mode 100644
index 3f2c2bc..0000000
--- a/modules/web-agent/bin/ignite-web-agent.sh
+++ /dev/null
@@ -1,87 +0,0 @@
-#!/bin/bash
-#
-# 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.
-#
-
-# Check JAVA_HOME.
-if [ "$JAVA_HOME" = "" ]; then
-    JAVA=`type -p java`
-    RETCODE=$?
-
-    if [ $RETCODE -ne 0 ]; then
-        echo $0", ERROR:"
-        echo "JAVA_HOME environment variable is not found."
-        echo "Please point JAVA_HOME variable to location of JDK 1.7 or JDK 1.8."
-        echo "You can also download latest JDK at http://java.com/download"
-
-        exit 1
-    fi
-
-    JAVA_HOME=
-else
-    JAVA=${JAVA_HOME}/bin/java
-fi
-
-#
-# Check JDK.
-#
-if [ ! -e "$JAVA" ]; then
-    echo $0", ERROR:"
-    echo "JAVA is not found in JAVA_HOME=$JAVA_HOME."
-    echo "Please point JAVA_HOME variable to installation of JDK 1.7 or JDK 1.8."
-    echo "You can also download latest JDK at http://java.com/download"
-
-    exit 1
-fi
-
-JAVA_VER=`"$JAVA" -version 2>&1 | egrep "1\.[78]\."`
-
-if [ "$JAVA_VER" == "" ]; then
-    echo $0", ERROR:"
-    echo "The version of JAVA installed in JAVA_HOME=$JAVA_HOME is incorrect."
-    echo "Please point JAVA_HOME variable to installation of JDK 1.7 or JDK 1.8."
-    echo "You can also download latest JDK at http://java.com/download"
-
-    exit 1
-fi
-
-SOURCE="${BASH_SOURCE[0]}"
-
-DIR="$( dirname "$SOURCE" )"
-
-while [ -h "$SOURCE" ]
-    do
-        SOURCE="$(readlink "$SOURCE")"
-
-        [[ $SOURCE != /* ]] && SOURCE="$DIR/$SOURCE"
-
-        DIR="$( cd -P "$( dirname "$SOURCE"  )" && pwd )"
-    done
-
-DIR="$( cd -P "$( dirname "$SOURCE" )" && pwd )"
-
-cd $DIR
-
-#
-# JVM options. See http://java.sun.com/javase/technologies/hotspot/vmoptions.jsp for more details.
-#
-# ADD YOUR/CHANGE ADDITIONAL OPTIONS HERE
-#
-if [ -z "$JVM_OPTS" ] ; then
-    JVM_OPTS="-Xms1g -Xmx1g -server -XX:+AggressiveOpts -XX:MaxPermSize=256m"
-fi
-
-"$JAVA" ${JVM_OPTS} -cp "*" org.apache.ignite.console.agent.AgentLauncher "$@"

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-agent/demo/README.txt
----------------------------------------------------------------------
diff --git a/modules/web-agent/demo/README.txt b/modules/web-agent/demo/README.txt
deleted file mode 100644
index 17e5074..0000000
--- a/modules/web-agent/demo/README.txt
+++ /dev/null
@@ -1,4 +0,0 @@
-Ignite Web Agent
-======================================
-
-This is folder for demo files.


[18/52] ignite git commit: Web Console beta-3.

Posted by ak...@apache.org.
http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/src/main/js/app/modules/loading/loading.module.js
----------------------------------------------------------------------
diff --git a/modules/web-console/src/main/js/app/modules/loading/loading.module.js b/modules/web-console/src/main/js/app/modules/loading/loading.module.js
deleted file mode 100644
index 889cd6b..0000000
--- a/modules/web-console/src/main/js/app/modules/loading/loading.module.js
+++ /dev/null
@@ -1,26 +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 angular from 'angular';
-
-import IgniteLoadingDirective from './loading.directive';
-import IgniteLoadingService from './loading.service';
-
-angular
-    .module('ignite-console.loading', [])
-    .directive(...IgniteLoadingDirective)
-    .service(...IgniteLoadingService);

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/src/main/js/app/modules/loading/loading.service.js
----------------------------------------------------------------------
diff --git a/modules/web-console/src/main/js/app/modules/loading/loading.service.js b/modules/web-console/src/main/js/app/modules/loading/loading.service.js
deleted file mode 100644
index ec31c1a..0000000
--- a/modules/web-console/src/main/js/app/modules/loading/loading.service.js
+++ /dev/null
@@ -1,48 +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 ['IgniteLoading', ['$timeout', ($timeout) => {
-    const _overlays = {};
-
-    const start = (key) => {
-        $timeout(() => {
-            const loadingOverlay = _overlays[key];
-
-            loadingOverlay && loadingOverlay.addClass('loading-active');
-        });
-    };
-
-    const finish = (key) => {
-        $timeout(() => {
-            const loadingOverlay = _overlays[key];
-
-            loadingOverlay && loadingOverlay.removeClass('loading-active');
-        });
-    };
-
-    const add = (key, element) => {
-        _overlays[key] = element;
-
-        return element;
-    };
-
-    return {
-        add,
-        start,
-        finish
-    };
-}]];

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/src/main/js/app/modules/navbar/Navbar.provider.js
----------------------------------------------------------------------
diff --git a/modules/web-console/src/main/js/app/modules/navbar/Navbar.provider.js b/modules/web-console/src/main/js/app/modules/navbar/Navbar.provider.js
deleted file mode 100644
index f1ae1b2..0000000
--- a/modules/web-console/src/main/js/app/modules/navbar/Navbar.provider.js
+++ /dev/null
@@ -1,28 +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 ['IgniteNavbar', [function() {
-    const items = [];
-
-    this.push = function(data) {
-        items.push(data);
-    };
-
-    this.$get = [function() {
-        return items;
-    }];
-}]];

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/src/main/js/app/modules/navbar/Userbar.provider.js
----------------------------------------------------------------------
diff --git a/modules/web-console/src/main/js/app/modules/navbar/Userbar.provider.js b/modules/web-console/src/main/js/app/modules/navbar/Userbar.provider.js
deleted file mode 100644
index 9513641..0000000
--- a/modules/web-console/src/main/js/app/modules/navbar/Userbar.provider.js
+++ /dev/null
@@ -1,28 +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 ['IgniteUserbar', [function() {
-    const items = [];
-
-    this.push = function(data) {
-        items.push(data);
-    };
-
-    this.$get = [function() {
-        return items;
-    }];
-}]];

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/src/main/js/app/modules/navbar/navbar.directive.js
----------------------------------------------------------------------
diff --git a/modules/web-console/src/main/js/app/modules/navbar/navbar.directive.js b/modules/web-console/src/main/js/app/modules/navbar/navbar.directive.js
deleted file mode 100644
index 020cfe4..0000000
--- a/modules/web-console/src/main/js/app/modules/navbar/navbar.directive.js
+++ /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.
- */
-
-export default ['igniteNavbar', ['IgniteNavbar', (IgniteNavbar) => {
-    function controller() {
-        const ctrl = this;
-
-        ctrl.items = IgniteNavbar;
-    }
-
-    return {
-        restrict: 'A',
-        controller,
-        controllerAs: 'navbar'
-    };
-}]];

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/src/main/js/app/modules/navbar/navbar.module.js
----------------------------------------------------------------------
diff --git a/modules/web-console/src/main/js/app/modules/navbar/navbar.module.js b/modules/web-console/src/main/js/app/modules/navbar/navbar.module.js
deleted file mode 100644
index b845cbc..0000000
--- a/modules/web-console/src/main/js/app/modules/navbar/navbar.module.js
+++ /dev/null
@@ -1,33 +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 angular from 'angular';
-
-import IgniteNavbar from './Navbar.provider';
-import IgniteUserbar from './Userbar.provider';
-
-import igniteNavbar from './navbar.directive';
-import igniteUserbar from './userbar.directive';
-
-angular
-.module('ignite-console.navbar', [
-
-])
-.provider(...IgniteNavbar)
-.provider(...IgniteUserbar)
-.directive(...igniteNavbar)
-.directive(...igniteUserbar);

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/src/main/js/app/modules/navbar/userbar.directive.js
----------------------------------------------------------------------
diff --git a/modules/web-console/src/main/js/app/modules/navbar/userbar.directive.js b/modules/web-console/src/main/js/app/modules/navbar/userbar.directive.js
deleted file mode 100644
index 0e94063..0000000
--- a/modules/web-console/src/main/js/app/modules/navbar/userbar.directive.js
+++ /dev/null
@@ -1,48 +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 ['igniteUserbar', [function() {
-    return {
-        restrict: 'A',
-        controller: ['$rootScope', 'IgniteUserbar', function($root, IgniteUserbar) {
-            const ctrl = this;
-
-            ctrl.items = [
-                {text: 'Profile', sref: 'settings.profile'},
-                {text: 'Getting Started', click: 'gettingStarted.tryShow(true)'}
-            ];
-
-            const _rebuildSettings = (event, user) => {
-                ctrl.items.splice(2);
-
-                if (!user.becomeUsed && user.admin)
-                    ctrl.items.push({text: 'Admin Panel', sref: 'settings.admin'});
-
-                ctrl.items.push(...IgniteUserbar);
-
-                if (!user.becomeUsed)
-                    ctrl.items.push({text: 'Log Out', sref: 'logout'});
-            };
-
-            if ($root.user)
-                _rebuildSettings(null, $root.user);
-
-            $root.$on('user', _rebuildSettings);
-        }],
-        controllerAs: 'userbar'
-    };
-}]];

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/src/main/js/app/modules/query-notebooks/query-notebooks.module.js
----------------------------------------------------------------------
diff --git a/modules/web-console/src/main/js/app/modules/query-notebooks/query-notebooks.module.js b/modules/web-console/src/main/js/app/modules/query-notebooks/query-notebooks.module.js
deleted file mode 100644
index 5999948..0000000
--- a/modules/web-console/src/main/js/app/modules/query-notebooks/query-notebooks.module.js
+++ /dev/null
@@ -1,115 +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 angular from 'angular';
-
-angular
-    .module('ignite-console.query-notebooks', [
-
-    ])
-    .provider('QueryNotebooks', function() {
-        const _demoNotebook = {
-            name: 'SQL demo',
-            paragraphs: [
-                {
-                    name: 'Query with refresh rate',
-                    cacheName: 'CarCache',
-                    pageSize: 50,
-                    query: 'SELECT count(*)\nFROM "CarCache".Car',
-                    result: 'bar',
-                    timeLineSpan: '1',
-                    rate: {
-                        value: 3,
-                        unit: 1000,
-                        installed: true
-                    }
-                },
-                {
-                    name: 'Simple query',
-                    cacheName: 'CarCache',
-                    pageSize: 50,
-                    query: 'SELECT * FROM "CarCache".Car',
-                    result: 'table',
-                    timeLineSpan: '1',
-                    rate: {
-                        value: 30,
-                        unit: 1000,
-                        installed: false
-                    }
-                },
-                {
-                    name: 'Query with aggregates',
-                    cacheName: 'CarCache',
-                    pageSize: 50,
-                    query: 'SELECT p.name, count(*) AS cnt\nFROM "ParkingCache".Parking p\nINNER JOIN "CarCache".Car c\n  ON (p.id) = (c.parkingId)\nGROUP BY P.NAME',
-                    result: 'table',
-                    timeLineSpan: '1',
-                    rate: {
-                        value: 30,
-                        unit: 1000,
-                        installed: false
-                    }
-                }
-            ],
-            expandedParagraphs: [0, 1, 2]
-        };
-
-        this.$get = ['$q', '$http', '$rootScope', ($q, $http, $root) => {
-            return {
-                read(noteId) {
-                    if ($root.IgniteDemoMode)
-                        return $q.when(angular.copy(_demoNotebook));
-
-                    return $http.post('/api/v1/notebooks/get', {noteId})
-                        .then(({data}) => data)
-                        .catch(({data}) => $q.reject(data));
-                },
-                save(notebook) {
-                    if ($root.IgniteDemoMode)
-                        return $q.when();
-
-                    return $http.post('/api/v1/notebooks/save', notebook)
-                        .then(({data}) => data)
-                        .catch(({data}) => $q.reject(data));
-                },
-                remove(notebook) {
-                    if ($root.IgniteDemoMode)
-                        return $q.reject(`Removing "${notebook.name}" notebook is not supported.`);
-
-                    return $http.post('/api/v1/notebooks/remove', {_id: notebook._id})
-                        .then(() => {
-                            const idx = _.findIndex($root.notebooks, (item) => {
-                                return item._id === notebook._id;
-                            });
-
-                            if (idx >= 0) {
-                                $root.notebooks.splice(idx, 1);
-
-                                $root.rebuildDropdown();
-
-                                if (idx < $root.notebooks.length)
-                                    return $root.notebooks[idx];
-                            }
-
-                            if ($root.notebooks.length > 0)
-                                return $root.notebooks[$root.notebooks.length - 1];
-                        })
-                        .catch(({data}) => $q.reject(data));
-                }
-            };
-        }];
-    });

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/src/main/js/app/modules/socket.module.js
----------------------------------------------------------------------
diff --git a/modules/web-console/src/main/js/app/modules/socket.module.js b/modules/web-console/src/main/js/app/modules/socket.module.js
deleted file mode 100644
index 17856c4..0000000
--- a/modules/web-console/src/main/js/app/modules/socket.module.js
+++ /dev/null
@@ -1,41 +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 angular from 'angular';
-import io from 'socket.io-client'; // eslint-disable-line no-unused-vars
-
-angular
-.module('ignite-console.socket', [
-])
-.provider('igniteSocketFactory', [function() {
-    let _options = {};
-
-    /**
-     * @param {Object} options Socket io options.
-     */
-    this.set = (options) => {
-        _options = options;
-    };
-
-    this.$get = ['socketFactory', function(socketFactory) {
-        return () => {
-            const ioSocket = io.connect(_options);
-
-            return socketFactory({ioSocket});
-        };
-    }];
-}]);

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/src/main/js/app/modules/states/admin.state.js
----------------------------------------------------------------------
diff --git a/modules/web-console/src/main/js/app/modules/states/admin.state.js b/modules/web-console/src/main/js/app/modules/states/admin.state.js
deleted file mode 100644
index af1fbde..0000000
--- a/modules/web-console/src/main/js/app/modules/states/admin.state.js
+++ /dev/null
@@ -1,34 +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 angular from 'angular';
-
-angular
-.module('ignite-console.states.admin', [
-    'ui.router'
-])
-.config(['$stateProvider', function($stateProvider) {
-    // set up the states
-    $stateProvider
-    .state('settings.admin', {
-        url: '/admin',
-        templateUrl: '/settings/admin.html',
-        metaTags: {
-            title: 'List of registered users'
-        }
-    });
-}]);

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/src/main/js/app/modules/states/configuration.state.js
----------------------------------------------------------------------
diff --git a/modules/web-console/src/main/js/app/modules/states/configuration.state.js b/modules/web-console/src/main/js/app/modules/states/configuration.state.js
deleted file mode 100644
index 7e5e95e..0000000
--- a/modules/web-console/src/main/js/app/modules/states/configuration.state.js
+++ /dev/null
@@ -1,226 +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 angular from 'angular';
-
-// Common directives.
-import previewPanel from './configuration/preview-panel.directive.js';
-
-// Clusters screen.
-import clustersGeneral from './configuration/clusters/general.directive';
-
-import clustersGeneralDiscoveryCloud from './configuration/clusters/general/discovery/cloud.directive';
-import clustersGeneralDiscoveryGoogle from './configuration/clusters/general/discovery/google.directive';
-import clustersGeneralDiscoveryJdbc from './configuration/clusters/general/discovery/jdbc.directive';
-import clustersGeneralDiscoveryMulticast from './configuration/clusters/general/discovery/multicast.directive';
-import clustersGeneralDiscoveryS3 from './configuration/clusters/general/discovery/s3.directive';
-import clustersGeneralDiscoveryShared from './configuration/clusters/general/discovery/shared.directive';
-import clustersGeneralDiscoveryVm from './configuration/clusters/general/discovery/vm.directive';
-
-import clustersGeneralDiscoveryZookeeper from './configuration/clusters/general/discovery/zookeeper.directive';
-import clustersGeneralDiscoveryZookeeperRetryExponential from './configuration/clusters/general/discovery/zookeeper/retrypolicy/exponential-backoff.directive';
-import clustersGeneralDiscoveryZookeeperRetryBoundedExponential from './configuration/clusters/general/discovery/zookeeper/retrypolicy/bounded-exponential-backoff.directive';
-import clustersGeneralDiscoveryZookeeperRetryUntilElapsed from './configuration/clusters/general/discovery/zookeeper/retrypolicy/until-elapsed.directive';
-import clustersGeneralDiscoveryZookeeperRetryNTimes from './configuration/clusters/general/discovery/zookeeper/retrypolicy/n-times.directive';
-import clustersGeneralDiscoveryZookeeperRetryOneTime from './configuration/clusters/general/discovery/zookeeper/retrypolicy/one-time.directive';
-import clustersGeneralDiscoveryZookeeperRetryForever from './configuration/clusters/general/discovery/zookeeper/retrypolicy/forever.directive';
-import clustersGeneralDiscoveryZookeeperRetryCustom from './configuration/clusters/general/discovery/zookeeper/retrypolicy/custom.directive';
-
-import clustersAtomic from './configuration/clusters/atomic.directive';
-import clustersBinary from './configuration/clusters/binary.directive';
-import clustersCommunication from './configuration/clusters/communication.directive';
-import clustersConnector from './configuration/clusters/connector.directive';
-import clustersDeployment from './configuration/clusters/deployment.directive';
-import clustersDiscovery from './configuration/clusters/discovery.directive';
-import clustersEvents from './configuration/clusters/events.directive';
-import clustersIgfs from './configuration/clusters/igfs.directive';
-import clustersMarshaller from './configuration/clusters/marshaller.directive';
-import clustersMetrics from './configuration/clusters/metrics.directive';
-import clustersSsl from './configuration/clusters/ssl.directive';
-import clustersSwap from './configuration/clusters/swap.directive';
-import clustersTime from './configuration/clusters/time.directive';
-import clustersThread from './configuration/clusters/thread.directive';
-import clustersTransactions from './configuration/clusters/transactions.directive';
-import clustersUserAttributes from './configuration/clusters/attributes.directive';
-import clustersCollision from './configuration/clusters/collision.directive';
-import clustersFailover from './configuration/clusters/failover.directive';
-import clustersLogger from './configuration/clusters/logger.directive';
-
-import clustersCollisionJobStealing from './configuration/clusters/collision/job-stealing.directive';
-import clustersCollisionFifoQueue from './configuration/clusters/collision/fifo-queue.directive';
-import clustersCollisionPriorityQueue from './configuration/clusters/collision/priority-queue.directive';
-import clustersCollisionCustom from './configuration/clusters/collision/custom.directive';
-
-import clustersLoggerLog4j2 from './configuration/clusters/logger/log4j2.directive';
-import clustersLoggerLog4j from './configuration/clusters/logger/log4j.directive';
-import clustersLoggerCustom from './configuration/clusters/logger/custom.directive';
-
-// Domains screen.
-import domainsGeneral from './configuration/domains/general.directive';
-import domainsQuery from './configuration/domains/query.directive';
-import domainsStore from './configuration/domains/store.directive';
-
-// Caches screen.
-import cachesGeneral from './configuration/caches/general.directive';
-import cachesMemory from './configuration/caches/memory.directive';
-import cachesQuery from './configuration/caches/query.directive';
-import cachesStore from './configuration/caches/store.directive';
-import cachesConcurrency from './configuration/caches/concurrency.directive';
-import cachesRebalance from './configuration/caches/rebalance.directive';
-import cachesServerNearCache from './configuration/caches/server-near-cache.directive';
-import cachesStatistics from './configuration/caches/statistics.directive';
-
-// IGFS screen.
-import igfsGeneral from './configuration/igfs/general.directive';
-import igfsIpc from './configuration/igfs/ipc.directive';
-import igfsFragmentizer from './configuration/igfs/fragmentizer.directive';
-import igfsDual from './configuration/igfs/dual.directive';
-import igfsSecondary from './configuration/igfs/secondary.directive';
-import igfsMisc from './configuration/igfs/misc.directive';
-
-// Summary screen.
-import ConfigurationSummaryCtrl from './configuration/summary/summary.controller';
-import ConfigurationSummaryResource from './configuration/summary/summary.resource';
-import summaryTabs from './configuration/summary/summary-tabs.directive';
-
-angular.module('ignite-console.states.configuration', ['ui.router'])
-    // Clusters screen.
-    .directive(...previewPanel)
-    .directive(...clustersLoggerCustom)
-    .directive(...clustersLoggerLog4j)
-    .directive(...clustersLoggerLog4j2)
-    .directive(...clustersLogger)
-    .directive(...clustersFailover)
-    .directive(...clustersCollisionCustom)
-    .directive(...clustersCollisionPriorityQueue)
-    .directive(...clustersCollisionFifoQueue)
-    .directive(...clustersCollisionJobStealing)
-    .directive(...clustersCollision)
-    .directive(...clustersUserAttributes)
-    .directive(...clustersTransactions)
-    .directive(...clustersThread)
-    .directive(...clustersTime)
-    .directive(...clustersSwap)
-    .directive(...clustersSsl)
-    .directive(...clustersMetrics)
-    .directive(...clustersMarshaller)
-    .directive(...clustersIgfs)
-    .directive(...clustersEvents)
-    .directive(...clustersDiscovery)
-    .directive(...clustersDeployment)
-    .directive(...clustersConnector)
-    .directive(...clustersCommunication)
-    .directive(...clustersBinary)
-    .directive(...clustersAtomic)
-    .directive(...clustersGeneral)
-    .directive(...clustersGeneralDiscoveryCloud)
-    .directive(...clustersGeneralDiscoveryGoogle)
-    .directive(...clustersGeneralDiscoveryJdbc)
-    .directive(...clustersGeneralDiscoveryMulticast)
-    .directive(...clustersGeneralDiscoveryS3)
-    .directive(...clustersGeneralDiscoveryShared)
-    .directive(...clustersGeneralDiscoveryVm)
-    .directive(...clustersGeneralDiscoveryZookeeper)
-    .directive(...clustersGeneralDiscoveryZookeeperRetryExponential)
-    .directive(...clustersGeneralDiscoveryZookeeperRetryBoundedExponential)
-    .directive(...clustersGeneralDiscoveryZookeeperRetryUntilElapsed)
-    .directive(...clustersGeneralDiscoveryZookeeperRetryNTimes)
-    .directive(...clustersGeneralDiscoveryZookeeperRetryOneTime)
-    .directive(...clustersGeneralDiscoveryZookeeperRetryForever)
-    .directive(...clustersGeneralDiscoveryZookeeperRetryCustom)
-    // Domains screen
-    .directive(...domainsGeneral)
-    .directive(...domainsQuery)
-    .directive(...domainsStore)
-    // Caches screen
-    .directive(...cachesGeneral)
-    .directive(...cachesMemory)
-    .directive(...cachesQuery)
-    .directive(...cachesStore)
-    .directive(...cachesConcurrency)
-    .directive(...cachesRebalance)
-    .directive(...cachesServerNearCache)
-    .directive(...cachesStatistics)
-    // IGFS screen
-    .directive(...igfsGeneral)
-    .directive(...igfsIpc)
-    .directive(...igfsFragmentizer)
-    .directive(...igfsDual)
-    .directive(...igfsSecondary)
-    .directive(...igfsMisc)
-    // Summary screen
-    .directive(...summaryTabs)
-    // Services.
-    .service(...ConfigurationSummaryResource)
-    // Configure state provider.
-    .config(['$stateProvider', ($stateProvider) => {
-        // Setup the states.
-        $stateProvider
-            .state('base.configuration', {
-                url: '/configuration',
-                templateUrl: '/configuration/sidebar.html'
-            })
-            .state('base.configuration.clusters', {
-                url: '/clusters',
-                templateUrl: '/configuration/clusters.html',
-                params: {
-                    linkId: null
-                },
-                metaTags: {
-                    title: 'Configure Clusters'
-                }
-            })
-            .state('base.configuration.caches', {
-                url: '/caches',
-                templateUrl: '/configuration/caches.html',
-                params: {
-                    linkId: null
-                },
-                metaTags: {
-                    title: 'Configure Caches'
-                }
-            })
-            .state('base.configuration.domains', {
-                url: '/domains',
-                templateUrl: '/configuration/domains.html',
-                params: {
-                    linkId: null
-                },
-                metaTags: {
-                    title: 'Configure Domain Model'
-                }
-            })
-            .state('base.configuration.igfs', {
-                url: '/igfs',
-                templateUrl: '/configuration/igfs.html',
-                params: {
-                    linkId: null
-                },
-                metaTags: {
-                    title: 'Configure IGFS'
-                }
-            })
-            .state('base.configuration.summary', {
-                url: '/summary',
-                templateUrl: '/configuration/summary.html',
-                controller: ConfigurationSummaryCtrl,
-                controllerAs: 'ctrl',
-                metaTags: {
-                    title: 'Configurations Summary'
-                }
-            });
-    }]);

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/src/main/js/app/modules/states/configuration/caches/concurrency.directive.js
----------------------------------------------------------------------
diff --git a/modules/web-console/src/main/js/app/modules/states/configuration/caches/concurrency.directive.js b/modules/web-console/src/main/js/app/modules/states/configuration/caches/concurrency.directive.js
deleted file mode 100644
index 9438679..0000000
--- a/modules/web-console/src/main/js/app/modules/states/configuration/caches/concurrency.directive.js
+++ /dev/null
@@ -1,27 +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 templateUrl from './concurrency.jade';
-
-export default ['igniteConfigurationCachesConcurrency', [() => {
-    return {
-        scope: true,
-        restrict: 'E',
-        templateUrl,
-        replace: true
-    };
-}]];

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/src/main/js/app/modules/states/configuration/caches/concurrency.jade
----------------------------------------------------------------------
diff --git a/modules/web-console/src/main/js/app/modules/states/configuration/caches/concurrency.jade b/modules/web-console/src/main/js/app/modules/states/configuration/caches/concurrency.jade
deleted file mode 100644
index 7cf8371..0000000
--- a/modules/web-console/src/main/js/app/modules/states/configuration/caches/concurrency.jade
+++ /dev/null
@@ -1,65 +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.
-
-include ../../../../../app/helpers/jade/mixins.jade
-
--var form = 'concurrency'
--var model = 'backupItem'
-
-form.panel.panel-default(name=form novalidate)
-    .panel-heading(bs-collapse-toggle='' ng-click='ui.loadPanel("#{form}")')
-        ignite-form-panel-chevron
-        label Concurrency control
-        ignite-form-field-tooltip.tipLabel
-            | Cache concurrent usage settings
-        ignite-form-revert
-    .panel-collapse(role='tabpanel' bs-collapse-target id=form)
-        .panel-body(ng-if='ui.isPanelLoaded("#{form}")')
-            .col-sm-6
-                .settings-row
-                    +number('Max async operations:', model + '.maxConcurrentAsyncOperations', 'maxConcurrentAsyncOperations', 'true', '500', '0',
-                        'Maximum number of allowed concurrent asynchronous operations<br/>\
-                        If 0 then number of concurrent asynchronous operations is unlimited')
-                .settings-row
-                    +number('Default lock timeout:', model + '.defaultLockTimeout', 'defaultLockTimeout', 'true', '0', '0',
-                        'Default lock acquisition timeout<br/>\
-                        If 0 then lock acquisition will never timeout')
-                .settings-row(ng-hide='#{model}.atomicityMode === "TRANSACTIONAL"')
-                    +dropdown('Entry versioning:', model + '.atomicWriteOrderMode', 'atomicWriteOrderMode', 'true', 'Choose versioning',
-                        '[\
-                            {value: "CLOCK", label: "CLOCK"},\
-                            {value: "PRIMARY", label: "PRIMARY"}\
-                        ]',
-                        'Write ordering mode determines which node assigns the write version, sender or the primary node:\
-                        <ul>\
-                            <li>CLOCK - in this mode write versions are assigned on a sender node which generally leads to better performance</li>\
-                            <li>PRIMARY - in this mode version is assigned only on primary node. This means that sender will only send write request to primary node, which in turn will assign write version and forward it to backups</li>\
-                        </ul>')
-                .settings-row
-                    +dropdown('Write synchronization mode:', model + '.writeSynchronizationMode', 'writeSynchronizationMode', 'true', 'PRIMARY_SYNC',
-                        '[\
-                            {value: "FULL_SYNC", label: "FULL_SYNC"},\
-                            {value: "FULL_ASYNC", label: "FULL_ASYNC"},\
-                            {value: "PRIMARY_SYNC", label: "PRIMARY_SYNC"}\
-                        ]',
-                        'Write synchronization mode:\
-                        <ul>\
-                            <li>FULL_SYNC - Ignite will wait for write or commit replies from all nodes</li>\
-                            <li>FULL_ASYNC - Ignite will not wait for write or commit responses from participating nodes</li>\
-                            <li>PRIMARY_SYNC - Makes sense for PARTITIONED mode. Ignite will wait for write or commit to complete on primary node</li>\
-                        </ul>')
-            .col-sm-6
-                +preview-xml-java(model, 'cacheConcurrency')

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/src/main/js/app/modules/states/configuration/caches/general.directive.js
----------------------------------------------------------------------
diff --git a/modules/web-console/src/main/js/app/modules/states/configuration/caches/general.directive.js b/modules/web-console/src/main/js/app/modules/states/configuration/caches/general.directive.js
deleted file mode 100644
index 3edc1a3..0000000
--- a/modules/web-console/src/main/js/app/modules/states/configuration/caches/general.directive.js
+++ /dev/null
@@ -1,27 +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 templateUrl from './general.jade';
-
-export default ['igniteConfigurationCachesGeneral', [() => {
-    return {
-        scope: true,
-        restrict: 'E',
-        templateUrl,
-        replace: true
-    };
-}]];

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/src/main/js/app/modules/states/configuration/caches/general.jade
----------------------------------------------------------------------
diff --git a/modules/web-console/src/main/js/app/modules/states/configuration/caches/general.jade b/modules/web-console/src/main/js/app/modules/states/configuration/caches/general.jade
deleted file mode 100644
index 44304bf..0000000
--- a/modules/web-console/src/main/js/app/modules/states/configuration/caches/general.jade
+++ /dev/null
@@ -1,65 +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.
-
-include ../../../../../app/helpers/jade/mixins.jade
-
--var model = 'backupItem'
-
-form.panel.panel-default(name='general' novalidate)
-    .panel-heading(bs-collapse-toggle)
-        ignite-form-panel-chevron
-        label General
-        ignite-form-revert
-    .panel-collapse(role='tabpanel' bs-collapse-target id='general')
-        .panel-body
-            .col-sm-6
-                .settings-row
-                    +text('Name:', model + '.name', 'cacheName', 'true', 'Input name', 'Cache name')
-                .settings-row
-                    +clusters(model, 'Associate clusters with the current cache')
-                .settings-row
-                    +dropdown-multiple('<span>Domain models:</span><a ui-sref="base.configuration.domains({linkId: linkId()})"> (add)</a>',
-                        model + '.domains', 'domains', 'true', 'Choose domain models', 'No domain models configured', 'domains',
-                        'Select domain models to describe types in cache')
-                .settings-row
-                    +cacheMode('Mode:', model + '.cacheMode', 'cacheMode', 'PARTITIONED')
-                .settings-row
-                    +dropdown('Atomicity:', model + '.atomicityMode', 'atomicityMode', 'true', 'ATOMIC',
-                        '[\
-                            {value: "ATOMIC", label: "ATOMIC"},\
-                            {value: "TRANSACTIONAL", label: "TRANSACTIONAL"}\
-                        ]',
-                        'Atomicity:\
-                        <ul>\
-                            <li>Atomic - in this mode distributed transactions and distributed locking are not supported</li>\
-                            <li>Transactional - in this mode specified fully ACID-compliant transactional cache behavior</li>\
-                        </ul>')
-                .settings-row(data-ng-show='#{model}.cacheMode === "PARTITIONED"')
-                    +number('Backups:', model + '.backups', 'backups', 'true', '0', '0', 'Number of nodes used to back up single partition for partitioned cache')
-                .settings-row(data-ng-show='#{model}.cacheMode === "PARTITIONED" && #{model}.backups')
-                    +checkbox('Read from backup', model + '.readFromBackup', 'readFromBackup',
-                        'Flag indicating whether data can be read from backup<br/>\
-                        If not set then always get data from primary node (never from backup)')
-                .settings-row
-                    +checkbox('Copy on read', model + '.copyOnRead', 'copyOnRead',
-                        'Flag indicating whether copy of the value stored in cache should be created for cache operation implying return value<br/>\
-                        Also if this flag is set copies are created for values passed to CacheInterceptor and to CacheEntryProcessor')
-                .settings-row(ng-show='#{model}.cacheMode === "PARTITIONED" && #{model}.atomicityMode === "TRANSACTIONAL"')
-                    +checkbox('Invalidate near cache', model + '.invalidate', 'invalidate',
-                        'Invalidation flag for near cache entries in transaction<br/>\
-                        If set then values will be invalidated (nullified) upon commit in near cache')
-            .col-sm-6
-                +preview-xml-java(model, 'cacheGeneral')

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/src/main/js/app/modules/states/configuration/caches/memory.directive.js
----------------------------------------------------------------------
diff --git a/modules/web-console/src/main/js/app/modules/states/configuration/caches/memory.directive.js b/modules/web-console/src/main/js/app/modules/states/configuration/caches/memory.directive.js
deleted file mode 100644
index c160b18..0000000
--- a/modules/web-console/src/main/js/app/modules/states/configuration/caches/memory.directive.js
+++ /dev/null
@@ -1,27 +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 templateUrl from './memory.jade';
-
-export default ['igniteConfigurationCachesMemory', [() => {
-    return {
-        scope: true,
-        restrict: 'E',
-        templateUrl,
-        replace: true
-    };
-}]];

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/src/main/js/app/modules/states/configuration/caches/memory.jade
----------------------------------------------------------------------
diff --git a/modules/web-console/src/main/js/app/modules/states/configuration/caches/memory.jade b/modules/web-console/src/main/js/app/modules/states/configuration/caches/memory.jade
deleted file mode 100644
index c862071..0000000
--- a/modules/web-console/src/main/js/app/modules/states/configuration/caches/memory.jade
+++ /dev/null
@@ -1,88 +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.
-
-include ../../../../../app/helpers/jade/mixins.jade
-
--var form = 'memory'
--var model = 'backupItem'
-
-form.panel.panel-default(name=form novalidate)
-    .panel-heading(bs-collapse-toggle='' ng-click='ui.loadPanel("#{form}")')
-        ignite-form-panel-chevron
-        label Memory
-        ignite-form-field-tooltip.tipLabel
-            | Cache memory settings
-        ignite-form-revert
-    .panel-collapse(role='tabpanel' bs-collapse-target id=form)
-        .panel-body(ng-if='ui.isPanelLoaded("#{form}")')
-            .col-sm-6
-                .settings-row
-                    +dropdown('Mode:', model + '.memoryMode', 'memoryMode', 'true', 'ONHEAP_TIERED',
-                        '[\
-                            {value: "ONHEAP_TIERED", label: "ONHEAP_TIERED"},\
-                            {value: "OFFHEAP_TIERED", label: "OFFHEAP_TIERED"},\
-                            {value: "OFFHEAP_VALUES", label: "OFFHEAP_VALUES"}\
-                        ]',
-                        'Memory modes:\
-                        <ul>\
-                            <li>\
-                                ONHEAP_TIERED - entries are cached on heap memory first<br/>\
-                                <ul>\
-                                    <li>\
-                                        If offheap memory is enabled and eviction policy evicts an entry from heap memory, entry will be moved to offheap memory<br/>\
-                                        If offheap memory is disabled, then entry is simply discarded\
-                                    </li>\
-                                    <li>\
-                                        If swap space is enabled and offheap memory fills up, then entry will be evicted into swap space<br/>\
-                                        If swap space is disabled, then entry will be discarded. If swap is enabled and offheap memory is disabled, then entry will be evicted directly from heap memory into swap\
-                                    </li>\
-                                </ul>\
-                            </li>\
-                            <li>\
-                                OFFHEAP_TIERED - works the same as ONHEAP_TIERED, except that entries never end up in heap memory and get stored in offheap memory right away<br/>\
-                                Entries get cached in offheap memory first and then get evicted to swap, if one is configured\
-                            </li>\
-                            <li>\
-                                OFFHEAP_VALUES - entry keys will be stored on heap memory, and values will be stored in offheap memory<br/>\
-                                Note that in this mode entries can be evicted only to swap\
-                            </li>\
-                        </ul>')
-                .settings-row(data-ng-show=model + '.memoryMode !== "OFFHEAP_VALUES"')
-                    +number-required('Off-heap max memory:', model + '.offHeapMaxMemory', 'offHeapMaxMemory', 'true',
-                        model + '.memoryMode === "OFFHEAP_TIERED"', '-1', '-1',
-                        'Sets maximum amount of memory available to off-heap storage<br/>\
-                        Possible values are:\
-                        <ul>\
-                            <li>-1 - means that off-heap storage is disabled</li>\
-                            <li>0 - Ignite will not limit off-heap storage (it is up to user to properly add and remove entries from cache to ensure that off-heap storage does not grow infinitely)</li>\
-                            <li>Any positive value specifies the limit of off-heap storage in bytes</li>\
-                        </ul>')
-                .settings-row
-                    -var onHeapTired = model + '.memoryMode === "ONHEAP_TIERED"'
-                    -var swapEnabled = model + '.swapEnabled'
-                    -var offHeapMaxMemory = model + '.offHeapMaxMemory'
-
-                    +evictionPolicy(model + '.evictionPolicy', 'evictionPolicy', 'true',
-                        onHeapTired  + ' && (' + swapEnabled + '|| _.isNumber(' + offHeapMaxMemory + ') &&' + offHeapMaxMemory + ' >= 0)',
-                        'Optional cache eviction policy<br/>\
-                        Must be set for entries to be evicted from on - heap to off - heap or swap')
-                .settings-row
-                    +number('Start size:', model + '.startSize', 'startSize', 'true', '1500000', '0',
-                        'Initial cache size which will be used to pre-create internal hash table after start')
-                .settings-row
-                    +checkbox('Swap enabled', model + '.swapEnabled', 'swapEnabled', 'Flag indicating whether swap storage is enabled or not for this cache')
-            .col-sm-6
-                +preview-xml-java(model, 'cacheMemory')

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/src/main/js/app/modules/states/configuration/caches/query.directive.js
----------------------------------------------------------------------
diff --git a/modules/web-console/src/main/js/app/modules/states/configuration/caches/query.directive.js b/modules/web-console/src/main/js/app/modules/states/configuration/caches/query.directive.js
deleted file mode 100644
index 9d8264e..0000000
--- a/modules/web-console/src/main/js/app/modules/states/configuration/caches/query.directive.js
+++ /dev/null
@@ -1,27 +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 templateUrl from './query.jade';
-
-export default ['igniteConfigurationCachesQuery', [() => {
-    return {
-        scope: true,
-        restrict: 'E',
-        templateUrl,
-        replace: true
-    };
-}]];

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/src/main/js/app/modules/states/configuration/caches/query.jade
----------------------------------------------------------------------
diff --git a/modules/web-console/src/main/js/app/modules/states/configuration/caches/query.jade b/modules/web-console/src/main/js/app/modules/states/configuration/caches/query.jade
deleted file mode 100644
index 2a6495b..0000000
--- a/modules/web-console/src/main/js/app/modules/states/configuration/caches/query.jade
+++ /dev/null
@@ -1,93 +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.
-
-include ../../../../../app/helpers/jade/mixins.jade
-
--var form = 'query'
--var model = 'backupItem'
-
-form.panel.panel-default(name=form novalidate)
-    .panel-heading(bs-collapse-toggle='' ng-click='ui.loadPanel("#{form}")')
-        ignite-form-panel-chevron
-        label Queries & Indexing
-        ignite-form-field-tooltip.tipLabel
-            | Cache queries settings
-        ignite-form-revert
-    .panel-collapse(role='tabpanel' bs-collapse-target id=form)
-        .panel-body(ng-if='ui.isPanelLoaded("#{form}")')
-            .col-sm-6
-                .settings-row
-                    +text('SQL schema name:', model + '.sqlSchema', 'sqlSchema', 'false', 'Input schema name', 'Schema name for cache according to SQL ANSI-99')
-                .settings-row
-                    +number('On-heap cache for off-heap indexes:', model + '.sqlOnheapRowCacheSize', 'sqlOnheapRowCacheSize', 'true', '10240', '1',
-                        'Number of SQL rows which will be cached onheap to avoid deserialization on each SQL index access')
-                .settings-row
-                    +number('Long query timeout:', model + '.longQueryWarningTimeout', 'longQueryWarningTimeout', 'true', '3000', '0',
-                        'Timeout in milliseconds after which long query warning will be printed')
-                .settings-row
-                    -var sqlFunctionClassesForm = 'querySqlFunctionClasses';
-                    -var sqlFunctionClasses = model + '.sqlFunctionClasses';
-
-                    ignite-form-group(ng-model=sqlFunctionClasses ng-form=sqlFunctionClassesForm)
-                        ignite-form-field-label
-                            | SQL functions
-                        ignite-form-group-tooltip
-                            | Collections of classes with user-defined functions for SQL queries
-                        ignite-form-group-add(ng-click='group.add = [{}]')
-                            | Add new user-defined functions for SQL queries
-
-                        -var uniqueTip = 'SQL function with such class name already exists!'
-
-                        .group-content(ng-if=sqlFunctionClasses + '.length')
-                            -var field = 'edit'
-                            -var valid = 'form[ngModelName].$valid'
-                            -var unique = 'form[ngModelName].$error.igniteUnique'
-                            -var save = sqlFunctionClasses + '[$index] = ' + field
-
-                            ignite-form-field(ng-repeat='model in #{sqlFunctionClasses} track by $index' type='internal' name='SQL function')
-                                .indexField
-                                    | {{ $index+1 }})
-                                +table-remove-button(sqlFunctionClasses, 'Remove user-defined function')
-
-                                span(ng-hide='field.edit')
-                                    a.labelFormField(ng-click='field.edit = true') {{ model }}
-                                span(ng-if='field.edit' ng-init='#{field} = model')
-                                    +table-java-class-field('SQL function', field, sqlFunctionClasses, valid, save, false)
-                                        +table-save-button(valid, save, false)
-                                        +unique-feedback(unique, uniqueTip)
-
-                        .group-content(ng-repeat='field in group.add')
-                            -var field = 'new'
-                            -var valid = 'form[ngModelName].$valid'
-                            -var unique = 'form[ngModelName].$error.igniteUnique'
-                            -var save = sqlFunctionClasses + '.push(' + field + ')'
-
-                            ignite-form-field(type='internal' name='SQL function')
-                                +table-java-class-field('SQL function', field, sqlFunctionClasses, valid, save, true)
-                                    +table-save-button(valid, save, true)
-                                    +unique-feedback(unique, uniqueTip)
-
-                        .group-content-empty(ng-if='!(#{sqlFunctionClasses}.length) && !group.add.length')
-                            | Not defined
-                .settings-row
-                    +checkbox('Snapshotable index', model + '.snapshotableIndex', 'snapshotableIndex',
-                        'Flag indicating whether SQL indexes should support snapshots')
-                .settings-row
-                    +checkbox('Escape table and filed names', model + '.sqlEscapeAll', 'sqlEscapeAll',
-                        'If set then all the SQL table and field names will be escaped with double quotes<br/>\
-                        This enforces case sensitivity for field names and also allows having special characters in table and field names')
-            .col-sm-6
-                +preview-xml-java(model, 'cacheQuery')

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/src/main/js/app/modules/states/configuration/caches/rebalance.directive.js
----------------------------------------------------------------------
diff --git a/modules/web-console/src/main/js/app/modules/states/configuration/caches/rebalance.directive.js b/modules/web-console/src/main/js/app/modules/states/configuration/caches/rebalance.directive.js
deleted file mode 100644
index 5081578..0000000
--- a/modules/web-console/src/main/js/app/modules/states/configuration/caches/rebalance.directive.js
+++ /dev/null
@@ -1,27 +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 templateUrl from './rebalance.jade';
-
-export default ['igniteConfigurationCachesRebalance', [() => {
-    return {
-        scope: true,
-        restrict: 'E',
-        templateUrl,
-        replace: true
-    };
-}]];

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/src/main/js/app/modules/states/configuration/caches/rebalance.jade
----------------------------------------------------------------------
diff --git a/modules/web-console/src/main/js/app/modules/states/configuration/caches/rebalance.jade b/modules/web-console/src/main/js/app/modules/states/configuration/caches/rebalance.jade
deleted file mode 100644
index 88026a2..0000000
--- a/modules/web-console/src/main/js/app/modules/states/configuration/caches/rebalance.jade
+++ /dev/null
@@ -1,65 +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.
-
-include ../../../../../app/helpers/jade/mixins.jade
-
--var form = 'rebalance'
--var model = 'backupItem'
-
-form.panel.panel-default(name=form novalidate ng-hide='#{model}.cacheMode === "LOCAL"')
-    .panel-heading(bs-collapse-toggle='' ng-click='ui.loadPanel("#{form}")')
-        ignite-form-panel-chevron
-        label Rebalance
-        ignite-form-field-tooltip.tipLabel
-            | Cache rebalance settings
-        ignite-form-revert
-    .panel-collapse(role='tabpanel' bs-collapse-target id=form)
-        .panel-body(ng-if='ui.isPanelLoaded("#{form}")')
-            .col-sm-6
-                .settings-row
-                    +dropdown('Mode:', model + '.rebalanceMode', 'rebalanceMode', 'true', 'ASYNC',
-                        '[\
-                            {value: "SYNC", label: "SYNC"},\
-                            {value: "ASYNC", label: "ASYNC"},\
-                            {value: "NONE", label: "NONE"}\
-                        ]',
-                        'Rebalance modes:\
-                        <ul>\
-                            <li>Synchronous - in this mode distributed caches will not start until all necessary data is loaded from other available grid nodes</li>\
-                            <li>Asynchronous - in this mode distributed caches will start immediately and will load all necessary data from other available grid nodes in the background</li>\
-                            <li>None - in this mode no rebalancing will take place which means that caches will be either loaded on demand from persistent store whenever data is accessed, or will be populated explicitly</li>\
-                        </ul>')
-                    .settings-row
-                        +number('Batch size:', model + '.rebalanceBatchSize', 'rebalanceBatchSize', 'true', '512 * 1024', '1',
-                            'Size (in bytes) to be loaded within a single rebalance message<br/>\
-                            Rebalancing algorithm will split total data set on every node into multiple batches prior to sending data')
-                    .settings-row
-                        +number('Batches prefetch count:', model + '.rebalanceBatchesPrefetchCount', 'rebalanceBatchesPrefetchCount', 'true', '2', '1',
-                            'Number of batches generated by supply node at rebalancing start')
-                    .settings-row
-                        +number('Order:', model + '.rebalanceOrder', 'rebalanceOrder', 'true', '0', Number.MIN_SAFE_INTEGER,
-                            'If cache rebalance order is positive, rebalancing for this cache will be started only when rebalancing for all caches with smaller rebalance order (except caches with rebalance order 0) will be completed')
-                    .settings-row
-                        +number('Delay:', model + '.rebalanceDelay', 'rebalanceDelay', 'true', '0', '0',
-                            'Delay in milliseconds upon a node joining or leaving topology (or crash) after which rebalancing should be started automatically')
-                    .settings-row
-                        +number('Timeout:', model + '.rebalanceTimeout', 'rebalanceTimeout', 'true', '10000', '0',
-                            'Rebalance timeout in milliseconds')
-                    .settings-row
-                        +number('Throttle:', model + '.rebalanceThrottle', 'rebalanceThrottle', 'true', '0', '0',
-                            'Time in milliseconds to wait between rebalance messages to avoid overloading of CPU or network')
-            .col-sm-6
-                +preview-xml-java(model, 'cacheRebalance')

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/src/main/js/app/modules/states/configuration/caches/server-near-cache.directive.js
----------------------------------------------------------------------
diff --git a/modules/web-console/src/main/js/app/modules/states/configuration/caches/server-near-cache.directive.js b/modules/web-console/src/main/js/app/modules/states/configuration/caches/server-near-cache.directive.js
deleted file mode 100644
index c2e83aa..0000000
--- a/modules/web-console/src/main/js/app/modules/states/configuration/caches/server-near-cache.directive.js
+++ /dev/null
@@ -1,27 +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 templateUrl from './server-near-cache.jade';
-
-export default ['igniteConfigurationCachesServerNearCache', [() => {
-    return {
-        scope: true,
-        restrict: 'E',
-        templateUrl,
-        replace: true
-    };
-}]];

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/src/main/js/app/modules/states/configuration/caches/server-near-cache.jade
----------------------------------------------------------------------
diff --git a/modules/web-console/src/main/js/app/modules/states/configuration/caches/server-near-cache.jade b/modules/web-console/src/main/js/app/modules/states/configuration/caches/server-near-cache.jade
deleted file mode 100644
index 2b1ca07..0000000
--- a/modules/web-console/src/main/js/app/modules/states/configuration/caches/server-near-cache.jade
+++ /dev/null
@@ -1,45 +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.
-
-include ../../../../../app/helpers/jade/mixins.jade
-
--var form = 'server-near-cache'
--var model = 'backupItem'
-
-form.panel.panel-default(name=form novalidate ng-show='#{model}.cacheMode === "PARTITIONED"')
-    .panel-heading(bs-collapse-toggle='' ng-click='ui.loadPanel("#{form}")')
-        ignite-form-panel-chevron
-        label Server near cache
-        ignite-form-field-tooltip.tipLabel
-            | Near cache settings#[br]
-            | Near cache is a small local cache that stores most recently or most frequently accessed data#[br]
-            | Should be used in case when it is impossible to send computations to remote nodes
-        ignite-form-revert
-    .panel-collapse(role='tabpanel' bs-collapse-target id=form)
-        .panel-body(ng-if='ui.isPanelLoaded("#{form}")')
-            .col-sm-6
-                -var enabled = model + '.nearCacheEnabled'
-                -var nearCfg = model + '.nearConfiguration'
-
-                .settings-row
-                    +checkbox('Enabled', enabled, 'nearCacheEnabled', 'Flag indicating whether to configure near cache')
-                .settings-row
-                    +number('Start size:', nearCfg + '.nearStartSize', 'nearStartSize', enabled, '375000', '0',
-                        'Initial cache size for near cache which will be used to pre-create internal hash table after start')
-                .settings-row
-                    +evictionPolicy(model + '.nearConfiguration.nearEvictionPolicy', 'nearCacheEvictionPolicy', enabled, 'false', 'Near cache eviction policy')
-            .col-sm-6
-                +preview-xml-java(model, 'cacheServerNearCache')

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/src/main/js/app/modules/states/configuration/caches/statistics.directive.js
----------------------------------------------------------------------
diff --git a/modules/web-console/src/main/js/app/modules/states/configuration/caches/statistics.directive.js b/modules/web-console/src/main/js/app/modules/states/configuration/caches/statistics.directive.js
deleted file mode 100644
index ee0da3d..0000000
--- a/modules/web-console/src/main/js/app/modules/states/configuration/caches/statistics.directive.js
+++ /dev/null
@@ -1,27 +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 templateUrl from './statistics.jade';
-
-export default ['igniteConfigurationCachesStatistics', [() => {
-    return {
-        scope: true,
-        restrict: 'E',
-        templateUrl,
-        replace: true
-    };
-}]];

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/src/main/js/app/modules/states/configuration/caches/statistics.jade
----------------------------------------------------------------------
diff --git a/modules/web-console/src/main/js/app/modules/states/configuration/caches/statistics.jade b/modules/web-console/src/main/js/app/modules/states/configuration/caches/statistics.jade
deleted file mode 100644
index cc2310a..0000000
--- a/modules/web-console/src/main/js/app/modules/states/configuration/caches/statistics.jade
+++ /dev/null
@@ -1,37 +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.
-
-include ../../../../../app/helpers/jade/mixins.jade
-
--var form = 'statistics'
--var model = 'backupItem'
-
-form.panel.panel-default(name=form novalidate)
-    .panel-heading(bs-collapse-toggle='' ng-click='ui.loadPanel("#{form}")')
-        ignite-form-panel-chevron
-        label Statistics
-        ignite-form-field-tooltip.tipLabel
-            | Cache statistics and management settings
-        ignite-form-revert
-    .panel-collapse(role='tabpanel' bs-collapse-target id=form)
-        .panel-body(ng-if='ui.isPanelLoaded("#{form}")')
-            .col-sm-6
-                .settings-row
-                    +checkbox('Statistics enabled', model + '.statisticsEnabled', 'statisticsEnabled', 'Flag indicating whether statistics gathering is enabled on a cache')
-                .settings-row
-                    +checkbox('Management enabled', model + '.managementEnabled', 'managementEnabled', 'Flag indicating whether management is enabled on this cache')
-            .col-sm-6
-                +preview-xml-java(model, 'cacheStatistics')

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/src/main/js/app/modules/states/configuration/caches/store.directive.js
----------------------------------------------------------------------
diff --git a/modules/web-console/src/main/js/app/modules/states/configuration/caches/store.directive.js b/modules/web-console/src/main/js/app/modules/states/configuration/caches/store.directive.js
deleted file mode 100644
index 80528e5..0000000
--- a/modules/web-console/src/main/js/app/modules/states/configuration/caches/store.directive.js
+++ /dev/null
@@ -1,27 +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 templateUrl from './store.jade';
-
-export default ['igniteConfigurationCachesStore', [() => {
-    return {
-        scope: true,
-        restrict: 'E',
-        templateUrl,
-        replace: true
-    };
-}]];


[13/52] ignite git commit: Web Console beta-3.

Posted by ak...@apache.org.
http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/src/main/js/app/modules/states/configuration/summary/summary.resource.js
----------------------------------------------------------------------
diff --git a/modules/web-console/src/main/js/app/modules/states/configuration/summary/summary.resource.js b/modules/web-console/src/main/js/app/modules/states/configuration/summary/summary.resource.js
deleted file mode 100644
index 0ef53ac..0000000
--- a/modules/web-console/src/main/js/app/modules/states/configuration/summary/summary.resource.js
+++ /dev/null
@@ -1,40 +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 ['ConfigurationSummaryResource', ['$q', '$http', ($q, $http) => {
-    const api = '/api/v1/configuration/clusters/list';
-
-    return {
-        read() {
-            return $http
-                .post(api)
-                .then(({data}) => data)
-                .then(({clusters, caches, igfss}) => {
-                    if (!clusters || !clusters.length)
-                        return {};
-
-                    _.forEach(clusters, (cluster) => {
-                        cluster.igfss = _.filter(igfss, ({_id}) => _.includes(cluster.igfss, _id));
-                        cluster.caches = _.filter(caches, ({_id}) => _.includes(cluster.caches, _id));
-                    });
-
-                    return {clusters};
-                })
-                .catch((err) => $q.reject(err));
-        }
-    };
-}]];

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/src/main/js/app/modules/states/logout.state.js
----------------------------------------------------------------------
diff --git a/modules/web-console/src/main/js/app/modules/states/logout.state.js b/modules/web-console/src/main/js/app/modules/states/logout.state.js
deleted file mode 100644
index 7f24a45..0000000
--- a/modules/web-console/src/main/js/app/modules/states/logout.state.js
+++ /dev/null
@@ -1,36 +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 angular from 'angular';
-
-angular
-.module('ignite-console.states.logout', [
-    'ui.router'
-])
-.config(['$stateProvider', function($stateProvider) {
-    // set up the states
-    $stateProvider
-    .state('logout', {
-        url: '/logout',
-        controller: ['Auth', function(Auth) {
-            Auth.logout();
-        }],
-        metaTags: {
-            title: 'Logout'
-        }
-    });
-}]);

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/src/main/js/app/modules/states/password.state.js
----------------------------------------------------------------------
diff --git a/modules/web-console/src/main/js/app/modules/states/password.state.js b/modules/web-console/src/main/js/app/modules/states/password.state.js
deleted file mode 100644
index 48d01df..0000000
--- a/modules/web-console/src/main/js/app/modules/states/password.state.js
+++ /dev/null
@@ -1,46 +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 angular from 'angular';
-
-angular
-.module('ignite-console.states.password', [
-    'ui.router'
-])
-.config(['$stateProvider', function($stateProvider) {
-    // set up the states
-    $stateProvider
-    .state('password', {
-        url: '/password',
-        abstract: true,
-        template: '<ui-view></ui-view>'
-    })
-    .state('password.reset', {
-        url: '/reset?{token}',
-        templateUrl: '/reset.html',
-        metaTags: {
-            title: 'Reset password'
-        }
-    })
-    .state('password.send', {
-        url: '/send',
-        templateUrl: '/reset.html',
-        metaTags: {
-            title: 'Password Send'
-        }
-    });
-}]);

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/src/main/js/app/modules/states/profile.state.js
----------------------------------------------------------------------
diff --git a/modules/web-console/src/main/js/app/modules/states/profile.state.js b/modules/web-console/src/main/js/app/modules/states/profile.state.js
deleted file mode 100644
index 8b6cdfe..0000000
--- a/modules/web-console/src/main/js/app/modules/states/profile.state.js
+++ /dev/null
@@ -1,34 +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 angular from 'angular';
-
-angular
-.module('ignite-console.states.profile', [
-    'ui.router'
-])
-.config(['$stateProvider', function($stateProvider) {
-    // set up the states
-    $stateProvider
-    .state('settings.profile', {
-        url: '/profile',
-        templateUrl: '/settings/profile.html',
-        metaTags: {
-            title: 'User profile'
-        }
-    });
-}]);

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/src/main/js/app/modules/states/signin.state.js
----------------------------------------------------------------------
diff --git a/modules/web-console/src/main/js/app/modules/states/signin.state.js b/modules/web-console/src/main/js/app/modules/states/signin.state.js
deleted file mode 100644
index a23a496..0000000
--- a/modules/web-console/src/main/js/app/modules/states/signin.state.js
+++ /dev/null
@@ -1,53 +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 angular from 'angular';
-import templateUrl from 'views/signin.jade';
-
-angular
-.module('ignite-console.states.login', [
-    'ui.router',
-    // services
-    'ignite-console.user'
-])
-.config(['$stateProvider', function($stateProvider) {
-    // set up the states
-    $stateProvider
-    .state('signin', {
-        url: '/',
-        templateUrl,
-        metaTags: {
-        }
-    });
-}])
-.run(['$rootScope', '$state', 'Auth', 'IgniteBranding', function($root, $state, Auth, branding) {
-    $root.$on('$stateChangeStart', function(event, toState) {
-        if (toState.name === branding.termsState)
-            return;
-
-        if (!Auth.authorized && (toState.name !== 'signin' && !_.startsWith(toState.name, 'password.'))) {
-            event.preventDefault();
-
-            $state.go('signin');
-        }
-        else if (Auth.authorized && toState.name === 'signin') {
-            event.preventDefault();
-
-            $state.go('base.configuration.clusters');
-        }
-    });
-}]);

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/src/main/js/app/modules/states/sql.state.js
----------------------------------------------------------------------
diff --git a/modules/web-console/src/main/js/app/modules/states/sql.state.js b/modules/web-console/src/main/js/app/modules/states/sql.state.js
deleted file mode 100644
index 1aa4f47..0000000
--- a/modules/web-console/src/main/js/app/modules/states/sql.state.js
+++ /dev/null
@@ -1,46 +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 angular from 'angular';
-
-angular
-.module('ignite-console.states.sql', [
-    'ui.router'
-])
-.config(['$stateProvider', function($stateProvider) {
-    // set up the states
-    $stateProvider
-    .state('base.sql', {
-        url: '/sql',
-        abstract: true,
-        template: '<ui-view></ui-view>'
-    })
-    .state('base.sql.notebook', {
-        url: '/notebook/{noteId}',
-        templateUrl: '/sql/sql.html',
-        metaTags: {
-            title: 'Query notebook'
-        }
-    })
-    .state('base.sql.demo', {
-        url: '/demo',
-        templateUrl: '/sql/sql.html',
-        metaTags: {
-            title: 'SQL demo'
-        }
-    });
-}]);

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/src/main/js/app/modules/user/Auth.service.js
----------------------------------------------------------------------
diff --git a/modules/web-console/src/main/js/app/modules/user/Auth.service.js b/modules/web-console/src/main/js/app/modules/user/Auth.service.js
deleted file mode 100644
index 080f4af..0000000
--- a/modules/web-console/src/main/js/app/modules/user/Auth.service.js
+++ /dev/null
@@ -1,76 +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 ['Auth', ['$http', '$rootScope', '$state', '$window', 'IgniteLegacyUtils', 'IgniteMessages', 'gettingStarted', 'User', 'IgniteAgentMonitor',
-    ($http, $root, $state, $window, LegacyUtils, Messages, gettingStarted, User, agentMonitor) => {
-        let _auth = false;
-
-        try {
-            _auth = localStorage.authorized === 'true';
-        }
-        catch (ignore) {
-            // No-op.
-        }
-
-        function _authorized(value) {
-            try {
-                return _auth = localStorage.authorized = !!value;
-            } catch (ignore) {
-                return _auth = !!value;
-            }
-        }
-
-        return {
-            get authorized() {
-                return _auth;
-            },
-            set authorized(auth) {
-                _authorized(auth);
-            },
-            forgotPassword(userInfo) {
-                return $http.post('/api/v1/password/forgot', userInfo)
-                    .success(() => $state.go('password.send'))
-                    .error((err) => LegacyUtils.showPopoverMessage(null, null, 'forgot_email', Messages.errorMessage(null, err)));
-            },
-            auth(action, userInfo) {
-                return $http.post('/api/v1/' + action, userInfo)
-                    .success(() => {
-                        return User.read().then((user) => {
-                            _authorized(true);
-
-                            $root.$broadcast('user', user);
-
-                            $state.go('base.configuration.clusters');
-
-                            $root.gettingStarted.tryShow();
-
-                            agentMonitor.init();
-                        });
-                    })
-                    .error((err) => LegacyUtils.showPopoverMessage(null, null, action + '_email', Messages.errorMessage(null, err)));
-            },
-            logout() {
-                return $http.post('/api/v1/logout')
-                    .then(() => {
-                        User.clean();
-
-                        $window.open($state.href('signin'), '_self');
-                    })
-                    .catch(Messages.showError);
-            }
-        };
-    }]];

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/src/main/js/app/modules/user/User.service.js
----------------------------------------------------------------------
diff --git a/modules/web-console/src/main/js/app/modules/user/User.service.js b/modules/web-console/src/main/js/app/modules/user/User.service.js
deleted file mode 100644
index d1f8083..0000000
--- a/modules/web-console/src/main/js/app/modules/user/User.service.js
+++ /dev/null
@@ -1,65 +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 ['User', ['$q', '$injector', '$rootScope', '$state', '$http', function($q, $injector, $root, $state, $http) {
-    let _user;
-
-    try {
-        _user = JSON.parse(localStorage.user);
-
-        if (_user)
-            $root.user = _user;
-    }
-    catch (ignore) {
-        // No-op.
-    }
-
-    return {
-        read() {
-            return $http.post('/api/v1/user').then(({data}) => {
-                if (_.isEmpty(data)) {
-                    const Auth = $injector.get('Auth');
-
-                    Auth.authorized = false;
-
-                    this.clean();
-
-                    if ($state.current.name !== 'signin')
-                        $state.go('signin');
-                }
-
-                try {
-                    localStorage.user = JSON.stringify(data);
-                }
-                catch (ignore) {
-                    // No-op.
-                }
-
-                return _user = $root.user = data;
-            });
-        },
-        clean() {
-            delete $root.user;
-
-            delete localStorage.user;
-
-            delete $root.IgniteDemoMode;
-
-            sessionStorage.removeItem('IgniteDemoMode');
-        }
-    };
-}]];

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/src/main/js/app/modules/user/user.module.js
----------------------------------------------------------------------
diff --git a/modules/web-console/src/main/js/app/modules/user/user.module.js b/modules/web-console/src/main/js/app/modules/user/user.module.js
deleted file mode 100644
index 2387f20..0000000
--- a/modules/web-console/src/main/js/app/modules/user/user.module.js
+++ /dev/null
@@ -1,28 +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 angular from 'angular';
-
-import Auth from './Auth.service';
-import User from './User.service';
-
-angular
-.module('ignite-console.user', [
-
-])
-.service(...Auth)
-.service(...User);

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/src/main/js/app/services/ChartColors.service.js
----------------------------------------------------------------------
diff --git a/modules/web-console/src/main/js/app/services/ChartColors.service.js b/modules/web-console/src/main/js/app/services/ChartColors.service.js
deleted file mode 100644
index 843aa5c..0000000
--- a/modules/web-console/src/main/js/app/services/ChartColors.service.js
+++ /dev/null
@@ -1,22 +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 COLORS from 'app/data/colors.json';
-
-export default ['IgniteChartColors', function() {
-    return COLORS;
-}];

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/src/main/js/app/services/Clone.service.js
----------------------------------------------------------------------
diff --git a/modules/web-console/src/main/js/app/services/Clone.service.js b/modules/web-console/src/main/js/app/services/Clone.service.js
deleted file mode 100644
index 52a4e4e..0000000
--- a/modules/web-console/src/main/js/app/services/Clone.service.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.
- */
-
-// Service for clone objects.
-export default ['IgniteClone', ['$rootScope', '$q', '$modal', ($root, $q, $modal) => {
-    const scope = $root.$new();
-
-    let _names = [];
-    let deferred;
-    let _validator;
-
-    function _nextAvailableName(name) {
-        let num = 1;
-        let tmpName = name;
-
-        while (_.includes(_names, tmpName)) {
-            tmpName = name + '_' + num.toString();
-
-            num++;
-        }
-
-        return tmpName;
-    }
-
-    const cloneModal = $modal({templateUrl: '/templates/clone.html', scope, placement: 'center', show: false});
-
-    scope.ok = function(newName) {
-        if (!_validator || _validator(newName)) {
-            deferred.resolve(_nextAvailableName(newName));
-
-            cloneModal.hide();
-        }
-    };
-
-    cloneModal.confirm = function(oldName, names, validator) {
-        _names = names;
-
-        scope.newName = _nextAvailableName(oldName);
-
-        _validator = validator;
-
-        deferred = $q.defer();
-
-        cloneModal.$promise.then(cloneModal.show);
-
-        return deferred.promise;
-    };
-
-    return cloneModal;
-}]];

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/src/main/js/app/services/Confirm.service.js
----------------------------------------------------------------------
diff --git a/modules/web-console/src/main/js/app/services/Confirm.service.js b/modules/web-console/src/main/js/app/services/Confirm.service.js
deleted file mode 100644
index c4e25a8..0000000
--- a/modules/web-console/src/main/js/app/services/Confirm.service.js
+++ /dev/null
@@ -1,70 +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.
- */
-
-// Confirm popup service.
-export default ['IgniteConfirm', ['$rootScope', '$q', '$modal', '$animate', ($root, $q, $modal, $animate) => {
-    const scope = $root.$new();
-
-    const modal = $modal({templateUrl: '/templates/confirm.html', scope, placement: 'center', show: false});
-
-    let deferred;
-
-    const _hide = (animate) => {
-        $animate.enabled(modal.$element, animate);
-
-        modal.hide();
-    };
-
-    scope.confirmYes = () => {
-        _hide(scope.animate);
-
-        deferred.resolve(true);
-    };
-
-    scope.confirmNo = () => {
-        _hide(scope.animate);
-
-        deferred.resolve(false);
-    };
-
-    scope.confirmCancel = () => {
-        _hide(true);
-
-        deferred.reject('cancelled');
-    };
-
-    /**
-     *
-     * @param {String } content
-     * @param {Boolean} [yesNo]
-     * @param {Boolean} [animate]
-     * @returns {Promise}
-     */
-    modal.confirm = (content, yesNo, animate) => {
-        scope.animate = !!animate;
-        scope.content = content || 'Confirm?';
-        scope.yesNo = !!yesNo;
-
-        deferred = $q.defer();
-
-        modal.$promise.then(modal.show);
-
-        return deferred.promise;
-    };
-
-    return modal;
-}]];

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/src/main/js/app/services/ConfirmBatch.service.js
----------------------------------------------------------------------
diff --git a/modules/web-console/src/main/js/app/services/ConfirmBatch.service.js b/modules/web-console/src/main/js/app/services/ConfirmBatch.service.js
deleted file mode 100644
index ef66335..0000000
--- a/modules/web-console/src/main/js/app/services/ConfirmBatch.service.js
+++ /dev/null
@@ -1,92 +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.
- */
-
-// Service for confirm or skip several steps.
-export default ['IgniteConfirmBatch', ['$rootScope', '$q', '$modal', ($root, $q, $modal) => {
-    const scope = $root.$new();
-
-    scope.confirmModal = $modal({
-        templateUrl: '/templates/batch-confirm.html',
-        scope,
-        placement: 'center',
-        show: false,
-        backdrop: 'static',
-        keyboard: false
-    });
-
-    const _done = (cancel) => {
-        scope.confirmModal.hide();
-
-        if (cancel)
-            scope.deferred.reject('cancelled');
-        else
-            scope.deferred.resolve();
-    };
-
-    const _nextElement = (skip) => {
-        scope.items[scope.curIx++].skip = skip;
-
-        if (scope.curIx < scope.items.length)
-            scope.content = scope.contentGenerator(scope.items[scope.curIx]);
-        else
-            _done();
-    };
-
-    scope.cancel = () => {
-        _done(true);
-    };
-
-    scope.skip = (applyToAll) => {
-        if (applyToAll) {
-            for (let i = scope.curIx; i < scope.items.length; i++)
-                scope.items[i].skip = true;
-
-            _done();
-        }
-        else
-            _nextElement(true);
-    };
-
-    scope.overwrite = (applyToAll) => {
-        if (applyToAll)
-            _done();
-        else
-            _nextElement(false);
-    };
-
-    return {
-        /**
-         * Show confirm all dialog.
-         *
-         * @param confirmMessageFn Function to generate a confirm message.
-         * @param itemsToConfirm Array of element to process by confirm.
-         */
-        confirm(confirmMessageFn, itemsToConfirm) {
-            scope.deferred = $q.defer();
-
-            scope.contentGenerator = confirmMessageFn;
-
-            scope.items = itemsToConfirm;
-            scope.curIx = 0;
-            scope.content = (scope.items && scope.items.length > 0) ? scope.contentGenerator(scope.items[0]) : null;
-
-            scope.confirmModal.$promise.then(scope.confirmModal.show);
-
-            return scope.deferred.promise;
-        }
-    };
-}]];

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/src/main/js/app/services/CopyToClipboard.service.js
----------------------------------------------------------------------
diff --git a/modules/web-console/src/main/js/app/services/CopyToClipboard.service.js b/modules/web-console/src/main/js/app/services/CopyToClipboard.service.js
deleted file mode 100644
index 74c4764..0000000
--- a/modules/web-console/src/main/js/app/services/CopyToClipboard.service.js
+++ /dev/null
@@ -1,50 +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.
- */
-
-// Service to copy some value to OS clipboard.
-export default ['IgniteCopyToClipboard', ['$window', 'IgniteMessages', ($window, Messages) => {
-    const body = angular.element($window.document.body);
-
-    const textArea = angular.element('<textarea/>');
-
-    textArea.css({
-        position: 'fixed',
-        opacity: '0'
-    });
-
-    return {
-        copy(toCopy) {
-            textArea.val(toCopy);
-
-            body.append(textArea);
-
-            textArea[0].select();
-
-            try {
-                if (document.execCommand('copy'))
-                    Messages.showInfo('Value copied to clipboard');
-                else
-                    window.prompt('Copy to clipboard: Ctrl+C, Enter', toCopy);  // eslint-disable-line no-alert
-            }
-            catch (err) {
-                window.prompt('Copy to clipboard: Ctrl+C, Enter', toCopy);  // eslint-disable-line no-alert
-            }
-
-            textArea.remove();
-        }
-    };
-}]];

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/src/main/js/app/services/Countries.service.js
----------------------------------------------------------------------
diff --git a/modules/web-console/src/main/js/app/services/Countries.service.js b/modules/web-console/src/main/js/app/services/Countries.service.js
deleted file mode 100644
index 5ad3e6a..0000000
--- a/modules/web-console/src/main/js/app/services/Countries.service.js
+++ /dev/null
@@ -1,31 +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 COUNTRIES from 'app/data/countries.json';
-
-export default ['IgniteCountries', function() {
-    const indexByName = _.keyBy(COUNTRIES, 'name');
-    const UNDEFINED_COUNTRY = {name: '', code: ''};
-
-    const getByName = (name) => (indexByName[name] || UNDEFINED_COUNTRY);
-    const getAll = () => (COUNTRIES);
-
-    return {
-        getByName,
-        getAll
-    };
-}];

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/src/main/js/app/services/Focus.service.js
----------------------------------------------------------------------
diff --git a/modules/web-console/src/main/js/app/services/Focus.service.js b/modules/web-console/src/main/js/app/services/Focus.service.js
deleted file mode 100644
index a07e181..0000000
--- a/modules/web-console/src/main/js/app/services/Focus.service.js
+++ /dev/null
@@ -1,33 +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.
- */
-
-// Service to transfer focus for specified element.
-export default ['IgniteFocus', ['$timeout', ($timeout) => {
-    return {
-        move(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(() => {
-                const elem = $('#' + id);
-
-                if (elem.length > 0)
-                    elem[0].focus();
-            }, 100);
-        }
-    };
-}]];

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/src/main/js/app/services/InetAddress.service.js
----------------------------------------------------------------------
diff --git a/modules/web-console/src/main/js/app/services/InetAddress.service.js b/modules/web-console/src/main/js/app/services/InetAddress.service.js
deleted file mode 100644
index abdd8a3..0000000
--- a/modules/web-console/src/main/js/app/services/InetAddress.service.js
+++ /dev/null
@@ -1,53 +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 ['IgniteInetAddress', function() {
-    return {
-        /**
-         * @param {String} ip IP address to check.
-         * @returns {boolean} 'true' if given ip address is valid.
-         */
-        validIp(ip) {
-            const regexp = /^(([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])$/;
-
-            return regexp.test(ip);
-        },
-        /**
-         * @param {String} hostNameOrIp host name or ip address to check.
-         * @returns {boolean} 'true' if given is host name or ip.
-         */
-        validHost(hostNameOrIp) {
-            const regexp = /^(([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 regexp.test(hostNameOrIp) || this.validIp(hostNameOrIp);
-        },
-        /**
-         * @param {int} port Port value to check.
-         * @returns boolean 'true' if given port is valid tcp/udp port range.
-         */
-        validPort(port) {
-            return _.isInteger(port) && port > 0 && port <= 65535;
-        },
-        /**
-         * @param {int} port Port value to check.
-         * @returns {boolean} 'true' if given port in non system port range(user+dynamic).
-         */
-        validNonSystemPort(port) {
-            return _.isInteger(port) && port >= 1024 && port <= 65535;
-        }
-    };
-}];

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/src/main/js/app/services/JavaTypes.service.js
----------------------------------------------------------------------
diff --git a/modules/web-console/src/main/js/app/services/JavaTypes.service.js b/modules/web-console/src/main/js/app/services/JavaTypes.service.js
deleted file mode 100644
index d34d669..0000000
--- a/modules/web-console/src/main/js/app/services/JavaTypes.service.js
+++ /dev/null
@@ -1,84 +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.
- */
-
-// Java built-in class names.
-import JAVA_CLASSES from 'app/data/java-classes.json';
-
-// Java build-in primitive.
-import JAVA_PRIMITIVES from 'app/data/java-primitives.json';
-
-import JAVA_KEYWORDS from 'app/data/java-keywords.json';
-
-export default ['JavaTypes', function() {
-    return {
-        /**
-         * @param {String} clsName Class name to check.
-         * @returns boolean 'true' if given class name non a Java built-in type.
-         */
-        nonBuiltInClass(clsName) {
-            return _.isNil(_.find(JAVA_CLASSES, (clazz) => clsName === clazz.short || clsName === clazz.full));
-        },
-        /**
-         * @param clsName Class name to check.
-         * @returns Full class name for java build-in types or source class otherwise.
-         */
-        fullClassName(clsName) {
-            const type = _.find(JAVA_CLASSES, (clazz) => clsName === clazz.short);
-
-            return type ? type.full : clsName;
-        },
-        /**
-         * @param {String} value text to check.
-         * @returns boolean 'true' if given text is valid Java identifier.
-         */
-        validIdentifier(value) {
-            const regexp = /^(([a-zA-Z_$][a-zA-Z0-9_$]*)\.)*([a-zA-Z_$][a-zA-Z0-9_$]*)$/igm;
-
-            return value === '' || regexp.test(value);
-        },
-        /**
-         * @param {String} value text to check.
-         * @returns boolean 'true' if given text is valid Java package.
-         */
-        validPackage(value) {
-            const regexp = /^(([a-zA-Z_$][a-zA-Z0-9_$]*)\.)*([a-zA-Z_$][a-zA-Z0-9_$]*(\.?\*)?)$/igm;
-
-            return value === '' || regexp.test(value);
-        },
-        /**
-         * @param {String} value text to check.
-         * @returns boolean 'true' if given text is a Java type with package.
-         */
-        packageSpecified(value) {
-            return value.split('.').length >= 2;
-        },
-        /**
-         * @param {String} value text to check.
-         * @returns boolean 'true' if given text non Java keyword.
-         */
-        isKeywords(value) {
-            return _.includes(JAVA_KEYWORDS, value);
-        },
-        /**
-         * @param {String} clsName Class name to check.
-         * @returns {boolean} 'true' if givent class name is java primitive.
-         */
-        isJavaPrimitive(clsName) {
-            return _.includes(JAVA_PRIMITIVES, clsName);
-        }
-    };
-}];

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/src/main/js/app/services/LegacyTable.service.js
----------------------------------------------------------------------
diff --git a/modules/web-console/src/main/js/app/services/LegacyTable.service.js b/modules/web-console/src/main/js/app/services/LegacyTable.service.js
deleted file mode 100644
index 8f3b791..0000000
--- a/modules/web-console/src/main/js/app/services/LegacyTable.service.js
+++ /dev/null
@@ -1,205 +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.
- */
-
-// TODO: Refactor this service for legacy tables with more than one input field.
-export default ['IgniteLegacyTable', ['IgniteLegacyUtils', 'IgniteFocus', (LegacyUtils, Focus) => {
-    function _model(item, field) {
-        return LegacyUtils.getModel(item, field);
-    }
-
-    const table = {name: 'none', editIndex: -1};
-
-    function _tableReset() {
-        delete table.field;
-        table.name = 'none';
-        table.editIndex = -1;
-
-        LegacyUtils.hidePopover();
-    }
-
-    function _tableSaveAndReset() {
-        const field = table.field;
-
-        const save = LegacyUtils.isDefined(field) && LegacyUtils.isDefined(field.save);
-
-        if (!save || !LegacyUtils.isDefined(field) || field.save(field, table.editIndex, true)) {
-            _tableReset();
-
-            return true;
-        }
-
-        return false;
-    }
-
-    function _tableState(field, editIndex, specName) {
-        table.field = field;
-        table.name = specName || field.model;
-        table.editIndex = editIndex;
-    }
-
-    function _tableUI(field) {
-        const ui = field.ui;
-
-        return ui ? ui : field.type;
-    }
-
-    function _tableFocus(focusId, index) {
-        Focus.move((index < 0 ? 'new' : 'cur') + focusId + (index >= 0 ? index : ''));
-    }
-
-    function _tablePairValue(filed, index) {
-        return index < 0 ? {key: filed.newKey, value: filed.newValue} : {key: filed.curKey, value: filed.curValue};
-    }
-
-    function _tableStartEdit(item, tbl, index, save) {
-        _tableState(tbl, index);
-
-        const val = _.get(_model(item, tbl), tbl.model)[index];
-
-        const ui = _tableUI(tbl);
-
-        tbl.save = save;
-
-        if (ui === 'table-pair') {
-            tbl.curKey = val[tbl.keyName];
-            tbl.curValue = val[tbl.valueName];
-
-            _tableFocus('Key' + tbl.focusId, index);
-        }
-        else if (ui === 'table-db-fields') {
-            tbl.curDatabaseFieldName = val.databaseFieldName;
-            tbl.curDatabaseFieldType = val.databaseFieldType;
-            tbl.curJavaFieldName = val.javaFieldName;
-            tbl.curJavaFieldType = val.javaFieldType;
-
-            _tableFocus('DatabaseFieldName' + tbl.focusId, index);
-        }
-        else if (ui === 'table-indexes') {
-            tbl.curIndexName = val.name;
-            tbl.curIndexType = val.indexType;
-            tbl.curIndexFields = val.fields;
-
-            _tableFocus(tbl.focusId, index);
-        }
-    }
-
-    function _tableNewItem(tbl) {
-        _tableState(tbl, -1);
-
-        const ui = _tableUI(tbl);
-
-        if (ui === 'table-pair') {
-            tbl.newKey = null;
-            tbl.newValue = null;
-
-            _tableFocus('Key' + tbl.focusId, -1);
-        }
-        else if (ui === 'table-db-fields') {
-            tbl.newDatabaseFieldName = null;
-            tbl.newDatabaseFieldType = null;
-            tbl.newJavaFieldName = null;
-            tbl.newJavaFieldType = null;
-
-            _tableFocus('DatabaseFieldName' + tbl.focusId, -1);
-        }
-        else if (ui === 'table-indexes') {
-            tbl.newIndexName = null;
-            tbl.newIndexType = 'SORTED';
-            tbl.newIndexFields = null;
-
-            _tableFocus(tbl.focusId, -1);
-        }
-    }
-
-    return {
-        tableState: _tableState,
-        tableReset: _tableReset,
-        tableSaveAndReset: _tableSaveAndReset,
-        tableNewItem: _tableNewItem,
-        tableNewItemActive(tbl) {
-            return table.name === tbl.model && table.editIndex < 0;
-        },
-        tableEditing(tbl, index) {
-            return table.name === tbl.model && table.editIndex === index;
-        },
-        tableEditedRowIndex() {
-            return table.editIndex;
-        },
-        tableField() {
-            return table.field;
-        },
-        tableStartEdit: _tableStartEdit,
-        tableRemove(item, field, index) {
-            _tableReset();
-
-            _.get(_model(item, field), field.model).splice(index, 1);
-        },
-        tablePairValue: _tablePairValue,
-        tablePairSave(pairValid, item, field, index, stopEdit) {
-            const valid = pairValid(item, field, index);
-
-            if (valid) {
-                const pairValue = _tablePairValue(field, index);
-
-                let pairModel = {};
-
-                const container = _.get(item, field.model);
-
-                if (index < 0) {
-                    pairModel[field.keyName] = pairValue.key;
-                    pairModel[field.valueName] = pairValue.value;
-
-                    if (container)
-                        container.push(pairModel);
-                    else
-                        _.set(item, field.model, [pairModel]);
-
-                    if (!stopEdit)
-                        _tableNewItem(field);
-                }
-                else {
-                    pairModel = container[index];
-
-                    pairModel[field.keyName] = pairValue.key;
-                    pairModel[field.valueName] = pairValue.value;
-
-                    if (!stopEdit) {
-                        if (index < container.length - 1)
-                            _tableStartEdit(item, field, index + 1);
-                        else
-                            _tableNewItem(field);
-                    }
-                }
-            }
-
-            return valid;
-        },
-        tablePairSaveVisible(field, index) {
-            const pairValue = _tablePairValue(field, index);
-
-            return !LegacyUtils.isEmptyString(pairValue.key) && !LegacyUtils.isEmptyString(pairValue.value);
-        },
-        tableFocusInvalidField(index, id) {
-            _tableFocus(id, index);
-
-            return false;
-        },
-        tableFieldId(index, id) {
-            return (index < 0 ? 'new' : 'cur') + id + (index >= 0 ? index : '');
-        }
-    };
-}]];

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/src/main/js/app/services/LegacyUtils.service.js
----------------------------------------------------------------------
diff --git a/modules/web-console/src/main/js/app/services/LegacyUtils.service.js b/modules/web-console/src/main/js/app/services/LegacyUtils.service.js
deleted file mode 100644
index c4c83e9..0000000
--- a/modules/web-console/src/main/js/app/services/LegacyUtils.service.js
+++ /dev/null
@@ -1,948 +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.
- */
-
-// TODO: Refactor this service for legacy tables with more than one input field.
-export default ['IgniteLegacyUtils', [
-    '$alert', '$popover', '$anchorScroll', '$location', '$timeout', '$window', 'IgniteFocus',
-    ($alert, $popover, $anchorScroll, $location, $timeout, $window, Focus) => {
-        $anchorScroll.yOffset = 55;
-
-        function isDefined(v) {
-            return !_.isNil(v);
-        }
-
-        function isEmptyString(s) {
-            if (isDefined(s))
-                return s.trim().length === 0;
-
-            return true;
-        }
-
-        const javaBuiltInClasses = [
-            'BigDecimal', 'Boolean', 'Byte', 'Date', 'Double', 'Float', 'Integer', 'Long', 'Object', 'Short', 'String', 'Time', 'Timestamp', 'UUID'
-        ];
-
-        const javaBuiltInTypes = [
-            'BigDecimal', 'boolean', 'Boolean', 'byte', 'Byte', 'Date', 'double', 'Double', 'float', 'Float',
-            'int', 'Integer', 'long', 'Long', 'Object', 'short', 'Short', 'String', 'Time', 'Timestamp', 'UUID'
-        ];
-
-        const javaBuiltInFullNameClasses = [
-            'java.math.BigDecimal', 'java.lang.Boolean', 'java.lang.Byte', 'java.sql.Date', 'java.lang.Double',
-            'java.lang.Float', 'java.lang.Integer', 'java.lang.Long', 'java.lang.Object', 'java.lang.Short',
-            'java.lang.String', 'java.sql.Time', 'java.sql.Timestamp', 'java.util.UUID'
-        ];
-
-        /**
-         * @param clsName Class name to check.
-         * @returns {Boolean} 'true' if given class name is a java build-in type.
-         */
-        function isJavaBuiltInClass(clsName) {
-            if (isEmptyString(clsName))
-                return false;
-
-            return _.includes(javaBuiltInClasses, clsName) || _.includes(javaBuiltInFullNameClasses, clsName);
-        }
-
-        const SUPPORTED_JDBC_TYPES = [
-            'BIGINT',
-            'BIT',
-            'BOOLEAN',
-            'BLOB',
-            'CHAR',
-            'CLOB',
-            'DATE',
-            'DECIMAL',
-            'DOUBLE',
-            'FLOAT',
-            'INTEGER',
-            'LONGNVARCHAR',
-            'LONGVARCHAR',
-            'NCHAR',
-            'NUMERIC',
-            'NVARCHAR',
-            'REAL',
-            'SMALLINT',
-            'TIME',
-            'TIMESTAMP',
-            'TINYINT',
-            'VARCHAR'
-        ];
-
-        const ALL_JDBC_TYPES = [
-            {dbName: 'BIT', dbType: -7, javaType: 'Boolean', primitiveType: 'boolean'},
-            {dbName: 'TINYINT', dbType: -6, javaType: 'Byte', primitiveType: 'byte'},
-            {dbName: 'SMALLINT', dbType: 5, javaType: 'Short', primitiveType: 'short'},
-            {dbName: 'INTEGER', dbType: 4, javaType: 'Integer', primitiveType: 'int'},
-            {dbName: 'BIGINT', dbType: -5, javaType: 'Long', primitiveType: 'long'},
-            {dbName: 'FLOAT', dbType: 6, javaType: 'Float', primitiveType: 'float'},
-            {dbName: 'REAL', dbType: 7, javaType: 'Double', primitiveType: 'double'},
-            {dbName: 'DOUBLE', dbType: 8, javaType: 'Double', primitiveType: 'double'},
-            {dbName: 'NUMERIC', dbType: 2, javaType: 'BigDecimal'},
-            {dbName: 'DECIMAL', dbType: 3, javaType: 'BigDecimal'},
-            {dbName: 'CHAR', dbType: 1, javaType: 'String'},
-            {dbName: 'VARCHAR', dbType: 12, javaType: 'String'},
-            {dbName: 'LONGVARCHAR', dbType: -1, javaType: 'String'},
-            {dbName: 'DATE', dbType: 91, javaType: 'Date'},
-            {dbName: 'TIME', dbType: 92, javaType: 'Time'},
-            {dbName: 'TIMESTAMP', dbType: 93, javaType: 'Timestamp'},
-            {dbName: 'BINARY', dbType: -2, javaType: 'Object'},
-            {dbName: 'VARBINARY', dbType: -3, javaType: 'Object'},
-            {dbName: 'LONGVARBINARY', dbType: -4, javaType: 'Object'},
-            {dbName: 'NULL', dbType: 0, javaType: 'Object'},
-            {dbName: 'OTHER', dbType: 1111, javaType: 'Object'},
-            {dbName: 'JAVA_OBJECT', dbType: 2000, javaType: 'Object'},
-            {dbName: 'DISTINCT', dbType: 2001, javaType: 'Object'},
-            {dbName: 'STRUCT', dbType: 2002, javaType: 'Object'},
-            {dbName: 'ARRAY', dbType: 2003, javaType: 'Object'},
-            {dbName: 'BLOB', dbType: 2004, javaType: 'Object'},
-            {dbName: 'CLOB', dbType: 2005, javaType: 'String'},
-            {dbName: 'REF', dbType: 2006, javaType: 'Object'},
-            {dbName: 'DATALINK', dbType: 70, javaType: 'Object'},
-            {dbName: 'BOOLEAN', dbType: 16, javaType: 'Boolean', primitiveType: 'boolean'},
-            {dbName: 'ROWID', dbType: -8, javaType: 'Object'},
-            {dbName: 'NCHAR', dbType: -15, javaType: 'String'},
-            {dbName: 'NVARCHAR', dbType: -9, javaType: 'String'},
-            {dbName: 'LONGNVARCHAR', dbType: -16, javaType: 'String'},
-            {dbName: 'NCLOB', dbType: 2011, javaType: 'String'},
-            {dbName: 'SQLXML', dbType: 2009, javaType: 'Object'}
-        ];
-
-        /*eslint-disable */
-        const JAVA_KEYWORDS = [
-            'abstract',     'assert',        'boolean',      'break',           'byte',
-            'case',         'catch',         'char',         'class',           'const',
-            'continue',     'default',       'do',           'double',          'else',
-            'enum',         'extends',       'false',        'final',           'finally',
-            'float',        'for',           'goto',         'if',              'implements',
-            'import',       'instanceof',    'int',          'interface',       'long',
-            'native',       'new',           'null',         'package',         'private',
-            'protected',    'public',        'return',       'short',           'static',
-            'strictfp',     'super',         'switch',       'synchronized',    'this',
-            'throw',        'throws',        'transient',    'true',            'try',
-            'void',         'volatile',      'while'
-        ];
-        /*eslint-enable */
-
-        const VALID_JAVA_IDENTIFIER = new RegExp('^[a-zA-Z_$][a-zA-Z\\d_$]*$');
-
-        let popover = null;
-
-        function isElementInViewport(el) {
-            const rect = el.getBoundingClientRect();
-
-            return (
-                rect.top >= 0 &&
-                rect.left >= 0 &&
-                rect.bottom <= (window.innerHeight || document.documentElement.clientHeight) &&
-                rect.right <= (window.innerWidth || document.documentElement.clientWidth)
-            );
-        }
-
-        const _showPopoverMessage = (id, message, showTime) => {
-            const body = $('body');
-
-            let el = body.find('#' + id);
-
-            if (!el || el.length === 0)
-                el = body.find('[name="' + id + '"]');
-
-            if (el && el.length > 0) {
-                if (!isElementInViewport(el[0])) {
-                    $location.hash(el[0].id);
-
-                    $anchorScroll();
-                }
-
-                const newPopover = $popover(el, {content: message});
-
-                popover = newPopover;
-
-                $timeout(() => newPopover.$promise.then(() => {
-                    newPopover.show();
-
-                    // Workaround to fix popover location when content is longer than content template.
-                    // https://github.com/mgcrea/angular-strap/issues/1497
-                    $timeout(newPopover.$applyPlacement);
-                }), 400);
-                $timeout(() => newPopover.hide(), showTime || 5000);
-            }
-        };
-
-        function ensureActivePanel(ui, pnl, focusId) {
-            if (ui) {
-                const collapses = $('div.panel-collapse');
-
-                ui.loadPanel(pnl);
-
-                const idx = _.findIndex(collapses, function(collapse) {
-                    return collapse.id === pnl;
-                });
-
-                if (idx >= 0) {
-                    const activePanels = ui.activePanels;
-
-                    if (!_.includes(ui.topPanels, idx)) {
-                        ui.expanded = true;
-
-                        const customExpanded = ui[pnl];
-
-                        if (customExpanded)
-                            ui[customExpanded] = true;
-                    }
-
-                    if (!activePanels || activePanels.length < 1)
-                        ui.activePanels = [idx];
-                    else if (!_.includes(activePanels, idx)) {
-                        const newActivePanels = angular.copy(activePanels);
-
-                        newActivePanels.push(idx);
-
-                        ui.activePanels = newActivePanels;
-                    }
-                }
-
-                if (isDefined(focusId))
-                    Focus.move(focusId);
-            }
-        }
-
-        function showPopoverMessage(ui, panelId, id, message, showTime) {
-            if (popover)
-                popover.hide();
-
-            if (ui) {
-                ensureActivePanel(ui, panelId);
-
-                $timeout(() => _showPopoverMessage(id, message, showTime), ui.isPanelLoaded(panelId) ? 200 : 500);
-            }
-            else
-                _showPopoverMessage(id, message, showTime);
-
-            return false;
-        }
-
-        function isValidJavaIdentifier(msg, ident, elemId, panels, panelId) {
-            if (isEmptyString(ident))
-                return showPopoverMessage(panels, panelId, elemId, msg + ' is invalid!');
-
-            if (_.includes(JAVA_KEYWORDS, ident))
-                return showPopoverMessage(panels, panelId, elemId, msg + ' could not contains reserved java keyword: "' + ident + '"!');
-
-            if (!VALID_JAVA_IDENTIFIER.test(ident))
-                return showPopoverMessage(panels, panelId, elemId, msg + ' contains invalid identifier: "' + ident + '"!');
-
-            return true;
-        }
-
-        let context = null;
-
-        /**
-         * Calculate width of specified text in body's font.
-         *
-         * @param text Text to calculate width.
-         * @returns {Number} Width of text in pixels.
-         */
-        function measureText(text) {
-            if (!context) {
-                const canvas = document.createElement('canvas');
-
-                context = canvas.getContext('2d');
-
-                const style = window.getComputedStyle(document.getElementsByTagName('body')[0]);
-
-                context.font = style.fontSize + ' ' + style.fontFamily;
-            }
-
-            return context.measureText(text).width;
-        }
-
-        /**
-         * Compact java full class name by max number of characters.
-         *
-         * @param names Array of class names to compact.
-         * @param nameLength Max available width in characters for simple name.
-         * @returns {*} Array of compacted class names.
-         */
-        function compactByMaxCharts(names, nameLength) {
-            for (let nameIx = 0; nameIx < names.length; nameIx++) {
-                const s = names[nameIx];
-
-                if (s.length > nameLength) {
-                    let totalLength = s.length;
-
-                    const packages = s.split('.');
-
-                    const packageCnt = packages.length - 1;
-
-                    for (let i = 0; i < packageCnt && totalLength > nameLength; i++) {
-                        if (packages[i].length > 0) {
-                            totalLength -= packages[i].length - 1;
-
-                            packages[i] = packages[i][0];
-                        }
-                    }
-
-                    if (totalLength > nameLength) {
-                        const className = packages[packageCnt];
-
-                        const classNameLen = className.length;
-
-                        let remains = Math.min(nameLength - totalLength + classNameLen, classNameLen);
-
-                        if (remains < 3)
-                            remains = Math.min(3, classNameLen);
-
-                        packages[packageCnt] = className.substring(0, remains) + '...';
-                    }
-
-                    let result = packages[0];
-
-                    for (let i = 1; i < packages.length; i++)
-                        result += '.' + packages[i];
-
-                    names[nameIx] = result;
-                }
-            }
-
-            return names;
-        }
-
-        /**
-         * Compact java full class name by max number of pixels.
-         *
-         * @param names Array of class names to compact.
-         * @param nameLength Max available width in characters for simple name. Used for calculation optimization.
-         * @param nameWidth Maximum available width in pixels for simple name.
-         * @returns {*} Array of compacted class names.
-         */
-        function compactByMaxPixels(names, nameLength, nameWidth) {
-            if (nameWidth <= 0)
-                return names;
-
-            const fitted = [];
-
-            const widthByName = [];
-
-            const len = names.length;
-
-            let divideTo = len;
-
-            for (let nameIx = 0; nameIx < len; nameIx++) {
-                fitted[nameIx] = false;
-
-                widthByName[nameIx] = nameWidth;
-            }
-
-            // Try to distribute space from short class names to long class names.
-            let remains = 0;
-
-            do {
-                for (let nameIx = 0; nameIx < len; nameIx++) {
-                    if (!fitted[nameIx]) {
-                        const curNameWidth = measureText(names[nameIx]);
-
-                        if (widthByName[nameIx] > curNameWidth) {
-                            fitted[nameIx] = true;
-
-                            remains += widthByName[nameIx] - curNameWidth;
-
-                            divideTo -= 1;
-
-                            widthByName[nameIx] = curNameWidth;
-                        }
-                    }
-                }
-
-                const remainsByName = remains / divideTo;
-
-                for (let nameIx = 0; nameIx < len; nameIx++) {
-                    if (!fitted[nameIx])
-                        widthByName[nameIx] += remainsByName;
-                }
-            }
-            while (remains > 0);
-
-            // Compact class names to available for each space.
-            for (let nameIx = 0; nameIx < len; nameIx++) {
-                const s = names[nameIx];
-
-                if (s.length > (nameLength / 2 | 0)) {
-                    let totalWidth = measureText(s);
-
-                    if (totalWidth > widthByName[nameIx]) {
-                        const packages = s.split('.');
-
-                        const packageCnt = packages.length - 1;
-
-                        for (let i = 0; i < packageCnt && totalWidth > widthByName[nameIx]; i++) {
-                            if (packages[i].length > 1) {
-                                totalWidth -= measureText(packages[i].substring(1, packages[i].length));
-
-                                packages[i] = packages[i][0];
-                            }
-                        }
-
-                        let shortPackage = '';
-
-                        for (let i = 0; i < packageCnt; i++)
-                            shortPackage += packages[i] + '.';
-
-                        const className = packages[packageCnt];
-
-                        const classLen = className.length;
-
-                        let minLen = Math.min(classLen, 3);
-
-                        totalWidth = measureText(shortPackage + className);
-
-                        // Compact class name if shorten package path is very long.
-                        if (totalWidth > widthByName[nameIx]) {
-                            let maxLen = classLen;
-                            let middleLen = (minLen + (maxLen - minLen) / 2 ) | 0;
-
-                            while (middleLen !== minLen && middleLen !== maxLen) {
-                                const middleLenPx = measureText(shortPackage + className.substr(0, middleLen) + '...');
-
-                                if (middleLenPx > widthByName[nameIx])
-                                    maxLen = middleLen;
-                                else
-                                    minLen = middleLen;
-
-                                middleLen = (minLen + (maxLen - minLen) / 2 ) | 0;
-                            }
-
-                            names[nameIx] = shortPackage + className.substring(0, middleLen) + '...';
-                        }
-                        else
-                            names[nameIx] = shortPackage + className;
-                    }
-                }
-            }
-
-            return names;
-        }
-
-        /**
-         * Compact any string by max number of pixels.
-         *
-         * @param label String to compact.
-         * @param nameWidth Maximum available width in pixels for simple name.
-         * @returns {*} Compacted string.
-         */
-        function compactLabelByPixels(label, nameWidth) {
-            if (nameWidth <= 0)
-                return label;
-
-            const totalWidth = measureText(label);
-
-            if (totalWidth > nameWidth) {
-                let maxLen = label.length;
-                let minLen = Math.min(maxLen, 3);
-                let middleLen = (minLen + (maxLen - minLen) / 2 ) | 0;
-
-                while (middleLen !== minLen && middleLen !== maxLen) {
-                    const middleLenPx = measureText(label.substr(0, middleLen) + '...');
-
-                    if (middleLenPx > nameWidth)
-                        maxLen = middleLen;
-                    else
-                        minLen = middleLen;
-
-                    middleLen = (minLen + (maxLen - minLen) / 2 ) | 0;
-                }
-
-                return label.substring(0, middleLen) + '...';
-            }
-
-            return label;
-        }
-
-        /**
-         * Calculate available width for text in link to edit element.
-         *
-         * @param index Showed index of element for calculation of maximum width in pixels.
-         * @param id Id of contains link table.
-         * @returns {*[]} First element is length of class for single value, second element is length for pair vlaue.
-         */
-        function availableWidth(index, id) {
-            const idElem = $('#' + id);
-
-            let width = 0;
-
-            switch (idElem.prop('tagName')) {
-                // Detection of available width in presentation table row.
-                case 'TABLE':
-                    const cont = $(idElem.find('tr')[index - 1]).find('td')[0];
-
-                    width = cont.clientWidth;
-
-                    if (width > 0) {
-                        const children = $(cont).children(':not("a")');
-
-                        _.forEach(children, function(child) {
-                            if ('offsetWidth' in child)
-                                width -= $(child).outerWidth(true);
-                        });
-                    }
-
-                    break;
-
-                // Detection of available width in dropdown row.
-                case 'A':
-                    width = idElem.width();
-
-                    $(idElem).children(':not("span")').each(function(ix, child) {
-                        if ('offsetWidth' in child)
-                            width -= child.offsetWidth;
-                    });
-
-                    break;
-
-                default:
-            }
-
-            return width | 0;
-        }
-
-        function getModel(obj, field) {
-            let path = field.path;
-
-            if (!isDefined(path) || !isDefined(obj))
-                return obj;
-
-            path = path.replace(/\[(\w+)\]/g, '.$1'); // convert indexes to properties
-            path = path.replace(/^\./, '');           // strip a leading dot
-
-            const segs = path.split('.');
-            let root = obj;
-
-            while (segs.length > 0) {
-                const pathStep = segs.shift();
-
-                if (typeof root[pathStep] === 'undefined')
-                    root[pathStep] = {};
-
-                root = root[pathStep];
-            }
-
-            return root;
-        }
-
-        function extractDataSource(cache) {
-            if (cache.cacheStoreFactory && cache.cacheStoreFactory.kind) {
-                const storeFactory = cache.cacheStoreFactory[cache.cacheStoreFactory.kind];
-
-                if (storeFactory.dialect || (storeFactory.connectVia === 'DataSource'))
-                    return storeFactory;
-            }
-
-            return null;
-        }
-
-        const cacheStoreJdbcDialects = [
-            {value: 'Generic', label: 'Generic JDBC'},
-            {value: 'Oracle', label: 'Oracle'},
-            {value: 'DB2', label: 'IBM DB2'},
-            {value: 'SQLServer', label: 'Microsoft SQL Server'},
-            {value: 'MySQL', label: 'MySQL'},
-            {value: 'PostgreSQL', label: 'PostgreSQL'},
-            {value: 'H2', label: 'H2 database'}
-        ];
-
-        function domainForStoreConfigured(domain) {
-            const isEmpty = !isDefined(domain) || (isEmptyString(domain.databaseSchema) &&
-                isEmptyString(domain.databaseTable) &&
-                _.isEmpty(domain.keyFields) &&
-                _.isEmpty(domain.valueFields));
-
-            return !isEmpty;
-        }
-
-        const DS_CHECK_SUCCESS = { checked: true };
-
-        function compareDataSources(firstCache, secondCache) {
-            const firstDs = extractDataSource(firstCache);
-            const secondDs = extractDataSource(secondCache);
-
-            if (firstDs && secondDs) {
-                const firstDB = firstDs.dialect;
-                const secondDB = secondDs.dialect;
-
-                if (firstDs.dataSourceBean === secondDs.dataSourceBean && firstDB !== secondDB)
-                    return {checked: false, firstCache, firstDB, secondCache, secondDB};
-            }
-
-            return DS_CHECK_SUCCESS;
-        }
-
-        function compareSQLSchemaNames(firstCache, secondCache) {
-            const firstName = firstCache.sqlSchema;
-            const secondName = secondCache.sqlSchema;
-
-            if (firstName && secondName && (firstName === secondName))
-                return {checked: false, firstCache, secondCache};
-
-            return DS_CHECK_SUCCESS;
-        }
-
-        function toJavaName(prefix, name) {
-            const javaName = name ? name.replace(/[^A-Za-z_0-9]+/g, '_') : 'dflt';
-
-            return prefix + javaName.charAt(0).toLocaleUpperCase() + javaName.slice(1);
-        }
-
-        return {
-            getModel,
-            mkOptions(options) {
-                return _.map(options, (option) => {
-                    return {value: option, label: isDefined(option) ? option : 'Not set'};
-                });
-            },
-            isDefined,
-            hasProperty(obj, props) {
-                for (const propName in props) {
-                    if (props.hasOwnProperty(propName)) {
-                        if (obj[propName])
-                            return true;
-                    }
-                }
-
-                return false;
-            },
-            isEmptyString,
-            SUPPORTED_JDBC_TYPES,
-            findJdbcType(jdbcType) {
-                const res = _.find(ALL_JDBC_TYPES, function(item) {
-                    return item.dbType === jdbcType;
-                });
-
-                return res ? res : {dbName: 'Unknown', javaType: 'Unknown'};
-            },
-            javaBuiltInClasses,
-            javaBuiltInTypes,
-            isJavaBuiltInClass,
-            isValidJavaIdentifier,
-            isValidJavaClass(msg, ident, allowBuiltInClass, elemId, packageOnly, panels, panelId) {
-                if (isEmptyString(ident))
-                    return showPopoverMessage(panels, panelId, elemId, msg + ' could not be empty!');
-
-                const parts = ident.split('.');
-
-                const len = parts.length;
-
-                if (!allowBuiltInClass && isJavaBuiltInClass(ident))
-                    return showPopoverMessage(panels, panelId, elemId, msg + ' should not be the Java build-in class!');
-
-                if (len < 2 && !isJavaBuiltInClass(ident) && !packageOnly)
-                    return showPopoverMessage(panels, panelId, elemId, msg + ' does not have package specified!');
-
-                for (let i = 0; i < parts.length; i++) {
-                    const part = parts[i];
-
-                    if (!isValidJavaIdentifier(msg, part, elemId, panels, panelId))
-                        return false;
-                }
-
-                return true;
-            },
-            domainForQueryConfigured(domain) {
-                const isEmpty = !isDefined(domain) || (_.isEmpty(domain.fields) &&
-                    _.isEmpty(domain.aliases) &&
-                    _.isEmpty(domain.indexes));
-
-                return !isEmpty;
-            },
-            domainForStoreConfigured,
-            /**
-             * Cut class name by width in pixel or width in symbol count.
-             *
-             * @param id Id of parent table.
-             * @param index Row number in table.
-             * @param maxLength Maximum length in symbols for all names.
-             * @param names Array of class names to compact.
-             * @param divider String to visualy divide items.
-             * @returns {*} Array of compacted class names.
-             */
-            compactJavaName(id, index, maxLength, names, divider) {
-                divider = ' ' + divider + ' ';
-
-                const prefix = index + ') ';
-
-                const nameCnt = names.length;
-
-                const nameLength = ((maxLength - 3 * (nameCnt - 1)) / nameCnt) | 0;
-
-                try {
-                    const nameWidth = (availableWidth(index, id) - measureText(prefix) - (nameCnt - 1) * measureText(divider)) /
-                        nameCnt | 0;
-
-                    // HTML5 calculation of showed message width.
-                    names = compactByMaxPixels(names, nameLength, nameWidth);
-                }
-                catch (err) {
-                    names = compactByMaxCharts(names, nameLength);
-                }
-
-                let result = prefix + names[0];
-
-                for (let nameIx = 1; nameIx < names.length; nameIx++)
-                    result += divider + names[nameIx];
-
-                return result;
-            },
-            /**
-             * Compact text by width in pixels or symbols count.
-             *
-             * @param id Id of parent table.
-             * @param index Row number in table.
-             * @param maxLength Maximum length in symbols for all names.
-             * @param label Text to compact.
-             * @returns Compacted label text.
-             */
-            compactTableLabel(id, index, maxLength, label) {
-                label = index + ') ' + label;
-
-                try {
-                    const nameWidth = availableWidth(index, id) | 0;
-
-                    // HTML5 calculation of showed message width.
-                    label = compactLabelByPixels(label, nameWidth);
-                }
-                catch (err) {
-                    const nameLength = maxLength - 3 | 0;
-
-                    label = label.length > maxLength ? label.substr(0, nameLength) + '...' : label;
-                }
-
-                return label;
-            },
-            widthIsSufficient(id, index, text) {
-                try {
-                    const available = availableWidth(index, id);
-
-                    const required = measureText(text);
-
-                    return !available || available >= Math.floor(required);
-                }
-                catch (err) {
-                    return true;
-                }
-            },
-            ensureActivePanel(panels, id, focusId) {
-                ensureActivePanel(panels, id, focusId);
-            },
-            showPopoverMessage,
-            hidePopover() {
-                if (popover)
-                    popover.hide();
-            },
-            confirmUnsavedChanges(dirty, selectFunc) {
-                if (dirty) {
-                    if ($window.confirm('You have unsaved changes.\n\nAre you sure you want to discard them?'))
-                        selectFunc();
-                }
-                else
-                    selectFunc();
-            },
-            saveBtnTipText(dirty, objectName) {
-                if (dirty)
-                    return 'Save ' + objectName;
-
-                return 'Nothing to save';
-            },
-            download(type, name, data) {
-                const file = document.createElement('a');
-
-                file.setAttribute('href', 'data:' + type + ';charset=utf-8,' + data);
-                file.setAttribute('download', name);
-                file.setAttribute('target', '_self');
-
-                file.style.display = 'none';
-
-                document.body.appendChild(file);
-
-                file.click();
-
-                document.body.removeChild(file);
-            },
-            formUI() {
-                return {
-                    ready: false,
-                    expanded: false,
-                    loadedPanels: [],
-                    loadPanel(pnl) {
-                        if (!_.includes(this.loadedPanels, pnl))
-                            this.loadedPanels.push(pnl);
-                    },
-                    isPanelLoaded(pnl) {
-                        return _.includes(this.loadedPanels, pnl);
-                    }
-                };
-            },
-            getQueryVariable(name) {
-                const attrs = window.location.search.substring(1).split('&');
-                const attr = _.find(attrs, (a) => a === name || (a.indexOf('=') >= 0 && a.substr(0, a.indexOf('=')) === name));
-
-                if (!isDefined(attr))
-                    return null;
-
-                if (attr === name)
-                    return true;
-
-                return attr.substr(attr.indexOf('=') + 1);
-            },
-            cacheStoreJdbcDialects,
-            cacheStoreJdbcDialectsLabel(dialect) {
-                const found = _.find(cacheStoreJdbcDialects, function(dialectVal) {
-                    return dialectVal.value === dialect;
-                });
-
-                return found ? found.label : null;
-            },
-            checkCachesDataSources(caches, checkCacheExt) {
-                let res = DS_CHECK_SUCCESS;
-
-                _.find(caches, function(curCache, curIx) {
-                    if (isDefined(checkCacheExt)) {
-                        if (checkCacheExt._id !== curCache._id) {
-                            res = compareDataSources(checkCacheExt, curCache);
-
-                            return !res.checked;
-                        }
-
-                        return false;
-                    }
-
-                    return _.find(caches, function(checkCache, checkIx) {
-                        if (checkIx < curIx) {
-                            res = compareDataSources(checkCache, curCache);
-
-                            return !res.checked;
-                        }
-
-                        return false;
-                    });
-                });
-
-                return res;
-            },
-            checkCacheSQLSchemas(caches, checkCacheExt) {
-                let res = DS_CHECK_SUCCESS;
-
-                _.find(caches, (curCache, curIx) => {
-                    if (isDefined(checkCacheExt)) {
-                        if (checkCacheExt._id !== curCache._id) {
-                            res = compareSQLSchemaNames(checkCacheExt, curCache);
-
-                            return !res.checked;
-                        }
-
-                        return false;
-                    }
-
-                    return _.find(caches, function(checkCache, checkIx) {
-                        if (checkIx < curIx) {
-                            res = compareSQLSchemaNames(checkCache, curCache);
-
-                            return !res.checked;
-                        }
-
-                        return false;
-                    });
-                });
-
-                return res;
-            },
-            autoCacheStoreConfiguration(cache, domains) {
-                const cacheStoreFactory = isDefined(cache.cacheStoreFactory) &&
-                    isDefined(cache.cacheStoreFactory.kind);
-
-                if (!cacheStoreFactory && _.findIndex(domains, domainForStoreConfigured) >= 0) {
-                    const dflt = !cache.readThrough && !cache.writeThrough;
-
-                    return {
-                        cacheStoreFactory: {
-                            kind: 'CacheJdbcPojoStoreFactory',
-                            CacheJdbcPojoStoreFactory: {
-                                dataSourceBean: toJavaName('ds', cache.name),
-                                dialect: 'Generic'
-                            },
-                            CacheJdbcBlobStoreFactory: { connectVia: 'DataSource' }
-                        },
-                        readThrough: dflt || cache.readThrough,
-                        writeThrough: dflt || cache.writeThrough
-                    };
-                }
-            },
-            autoClusterSwapSpiConfiguration(cluster, caches) {
-                const swapConfigured = cluster.swapSpaceSpi && cluster.swapSpaceSpi.kind;
-
-                if (!swapConfigured && _.find(caches, (cache) => cache.swapEnabled))
-                    return {swapSpaceSpi: {kind: 'FileSwapSpaceSpi'}};
-
-                return null;
-            },
-            randomString(len) {
-                const possible = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';
-                const possibleLen = possible.length;
-
-                let res = '';
-
-                for (let i = 0; i < len; i++)
-                    res += possible.charAt(Math.floor(Math.random() * possibleLen));
-
-                return res;
-            },
-            checkFieldValidators(ui) {
-                const form = ui.inputForm;
-                const errors = form.$error;
-                const errKeys = Object.keys(errors);
-
-                if (errKeys && errKeys.length > 0) {
-                    const firstErrorKey = errKeys[0];
-
-                    const firstError = errors[firstErrorKey][0];
-                    const actualError = firstError.$error[firstErrorKey][0];
-
-                    const errNameFull = actualError.$name;
-                    const errNameShort = errNameFull.endsWith('TextInput') ? errNameFull.substring(0, errNameFull.length - 9) : errNameFull;
-
-                    const extractErrorMessage = function(errName) {
-                        try {
-                            return errors[firstErrorKey][0].$errorMessages[errName][firstErrorKey];
-                        }
-                        catch (ignored) {
-                            try {
-                                return form[firstError.$name].$errorMessages[errName][firstErrorKey];
-                            }
-                            catch (ignited) {
-                                return false;
-                            }
-                        }
-                    };
-
-                    const msg = extractErrorMessage(errNameFull) || extractErrorMessage(errNameShort) || 'Invalid value!';
-
-                    return showPopoverMessage(ui, firstError.$name, errNameFull, msg);
-                }
-
-                return true;
-            }
-        };
-    }
-]];

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/src/main/js/app/services/Messages.service.js
----------------------------------------------------------------------
diff --git a/modules/web-console/src/main/js/app/services/Messages.service.js b/modules/web-console/src/main/js/app/services/Messages.service.js
deleted file mode 100644
index e679488..0000000
--- a/modules/web-console/src/main/js/app/services/Messages.service.js
+++ /dev/null
@@ -1,63 +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.
- */
-
-// Service to show various information and error messages.
-export default ['IgniteMessages', ['$alert', ($alert) => {
-    // Common instance of alert modal.
-    let msgModal;
-
-    const errorMessage = (prefix, err) => {
-        prefix = prefix || '';
-
-        if (err) {
-            if (err.hasOwnProperty('message'))
-                return prefix + err.message;
-
-            return prefix + err;
-        }
-
-        return prefix + 'Internal error.';
-    };
-
-    const hideAlert = () => {
-        if (msgModal)
-            msgModal.hide();
-    };
-
-    const _showMessage = (err, type, duration, icon) => {
-        hideAlert();
-
-        const title = errorMessage(null, err);
-
-        msgModal = $alert({type, title, duration});
-
-        msgModal.$scope.icon = icon;
-    };
-
-    return {
-        errorMessage,
-        hideAlert,
-        showError(err) {
-            _showMessage(err, 'danger', 10, 'fa-exclamation-triangle');
-
-            return false;
-        },
-        showInfo(err) {
-            _showMessage(err, 'success', 3, 'fa-check-circle-o');
-        }
-    };
-}]];


[24/52] ignite git commit: Web Console beta-3.

Posted by ak...@apache.org.
http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/frontend/public/stylesheets/_font-awesome-custom.scss
----------------------------------------------------------------------
diff --git a/modules/web-console/frontend/public/stylesheets/_font-awesome-custom.scss b/modules/web-console/frontend/public/stylesheets/_font-awesome-custom.scss
new file mode 100644
index 0000000..1c8f325
--- /dev/null
+++ b/modules/web-console/frontend/public/stylesheets/_font-awesome-custom.scss
@@ -0,0 +1,32 @@
+/*
+ * 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 '~font-awesome/scss/variables';
+
+$fa-font-path: '~font-awesome/fonts';
+
+@import '~font-awesome/scss/mixins';
+@import '~font-awesome/scss/path';
+@import '~font-awesome/scss/core';
+@import '~font-awesome/scss/larger';
+@import '~font-awesome/scss/fixed-width';
+@import '~font-awesome/scss/list';
+@import '~font-awesome/scss/bordered-pulled';
+@import '~font-awesome/scss/animated';
+@import '~font-awesome/scss/rotated-flipped';
+@import '~font-awesome/scss/stacked';
+@import '~font-awesome/scss/icons';

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/frontend/public/stylesheets/blocks/error.scss
----------------------------------------------------------------------
diff --git a/modules/web-console/frontend/public/stylesheets/blocks/error.scss b/modules/web-console/frontend/public/stylesheets/blocks/error.scss
new file mode 100644
index 0000000..4e16989
--- /dev/null
+++ b/modules/web-console/frontend/public/stylesheets/blocks/error.scss
@@ -0,0 +1,31 @@
+/*
+ * 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.
+ */
+
+.error-page {
+    text-align: center;
+    min-height: 300px;
+
+    &__title {
+        margin-top: 150px;
+        font-weight: 200;
+    }
+
+    &__description {
+        margin-top: 30px;
+        font-weight: 500;
+    }
+}

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/frontend/public/stylesheets/style.scss
----------------------------------------------------------------------
diff --git a/modules/web-console/frontend/public/stylesheets/style.scss b/modules/web-console/frontend/public/stylesheets/style.scss
new file mode 100644
index 0000000..4db7127
--- /dev/null
+++ b/modules/web-console/frontend/public/stylesheets/style.scss
@@ -0,0 +1,2171 @@
+/*
+ * 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 "./font-awesome-custom";
+@import "./bootstrap-custom";
+@import "./variables";
+@import "~roboto-font/css/fonts.css";
+@import "./../../app/directives/information/information.scss";
+@import "./blocks/error";
+
+hr {
+    margin: 20px 0;
+}
+
+.theme-line a.active {
+    font-weight: bold;
+    font-size: 1.1em;
+}
+
+.theme-line a:focus {
+    text-decoration: underline;
+    outline: none;
+}
+
+.navbar-default .navbar-brand, .navbar-default .navbar-brand:hover {
+    position: absolute;
+    left: 0;
+    text-align: center;
+}
+
+.navbar-brand {
+    padding: 5px 0;
+    margin: 10px 0;
+}
+
+.modal.center .modal-dialog {
+    position: fixed;
+    top: 50%;
+    left: 50%;
+    -webkit-transform: translateX(-50%) translateY(-50%);
+    transform: translateX(-50%) translateY(-50%);
+}
+
+.border-left {
+    box-shadow: 1px 0 0 0 $gray-lighter inset;
+}
+
+.border-right {
+    box-shadow: 1px 0 0 0 $gray-lighter;
+}
+
+.theme-line header {
+    background-color: $ignite-background-color;
+}
+
+.theme-line .docs-header h1 {
+    color: $ignite-header-color;
+    margin-top: 0;
+    font-size: 22px;
+}
+
+.theme-line .footer {
+    text-align: center;
+}
+
+.table.table-vertical-middle tbody > tr > td {
+  vertical-align: middle;
+}
+
+ul.navbar-nav, .sidebar-nav {
+    li.active > a {
+        color: $link-color;
+    }
+
+    li.active > a:not(.dropdown-toggle) {
+        cursor: default;
+        pointer-events: none;
+    }
+}
+
+.theme-line .sidebar-nav {
+    padding-bottom: 30px;
+
+    ul {
+        padding: 0;
+        list-style: none;
+        margin: 3px 0 0;
+
+        li {
+            line-height: $input-height;
+
+            a {
+                font-size: 18px;
+                color: $ignite-header-color;
+                position: relative;
+                white-space: nowrap;
+                overflow: hidden;
+                -o-text-overflow: ellipsis;
+                text-overflow: ellipsis;
+
+                span.fa-stack {
+                    margin-right: 5px;
+                    font-size: 12px;
+                    height: 26px;
+                }
+            }
+
+            a:hover { color: $link-hover-color; }
+
+            a.active {
+                color: $link-color;
+            }
+        }
+    }
+}
+
+.theme-line .sidebar-nav ul li a:hover {
+    text-decoration: none;
+}
+
+.theme-line .select {
+    li a.active {
+        color: $dropdown-link-active-color;
+    }
+
+    li a:hover {
+        color: $dropdown-link-hover-color;
+    }
+}
+
+.theme-line .select,
+.theme-line .typeahead {
+    .active {
+        font-size: 1em;
+        background-color: $gray-lighter;
+    }
+}
+
+.theme-line button.form-control.placeholder {
+    color: $input-color-placeholder;
+}
+
+.theme-line .summary-pojo-list > ul.dropdown-menu {
+    width: 100%;
+    max-width: none;
+}
+
+.tooltip {
+  word-wrap: break-word;
+}
+
+.theme-line ul.dropdown-menu {
+    min-width: 120px;
+    max-width: 280px;
+    max-height: 20em;
+    overflow: auto;
+    overflow-x: hidden;
+    outline-style: none;
+    margin-top: 0;
+
+    li > a {
+        display: block;
+
+        padding: 3px 10px;
+
+        overflow: hidden;
+        white-space: nowrap;
+        text-overflow: ellipsis;
+
+        i {
+            float: right;
+            color: $brand-primary;
+            background-color: transparent;
+            line-height: $line-height-base;
+            margin-left: 5px;
+            margin-right: 0;
+        }
+    }
+
+    li > div {
+        display: block;
+        overflow: hidden;
+
+        i {
+            float: right;
+            color: $text-color;
+            background-color: transparent;
+            line-height: $line-height-base;
+            margin: 0 10px 0 0;
+            padding: 6px 0;
+        }
+
+        div {
+            overflow: hidden;
+            text-overflow: ellipsis;
+        }
+    }
+
+    // Hover/Focus state
+    li > div a {
+        float: left;
+        display: block;
+        width: 100%;
+        padding: 3px 10px;
+        color: $dropdown-link-color;
+
+        overflow: hidden;
+        white-space: nowrap;
+        text-overflow: ellipsis;
+        
+        &:hover,
+        &:focus {
+            text-decoration: none;
+            color: $dropdown-link-hover-color;
+            background-color: $dropdown-link-hover-bg;
+        }
+    }
+
+    // Active state
+    .active > div a {
+        cursor: default;
+        pointer-events: none;
+
+        &,
+        &:hover,
+        &:focus {
+            color: $dropdown-link-active-color;
+            text-decoration: none;
+            outline: 0;
+            background-color: $dropdown-link-active-bg;
+        }
+    }
+
+    li.divider {
+        margin: 3px 0;
+    }
+}
+
+.theme-line .border-left .sidebar-nav {
+    padding-left: 15px;
+}
+
+.theme-line .suggest {
+    padding: 5px;
+    display: inline-block;
+    font-size: 12px;
+}
+
+.theme-line header {
+    border-bottom: 8px solid $ignite-border-bottom-color;
+
+    p {
+        color: $ignite-header-color;
+    }
+}
+
+.header .nav.navbar-nav.pull-right > li > a {
+    padding-right: 0;
+}
+
+.header .title {
+    margin: 20px 0 5px 0;
+    padding: 0 15px;
+
+    font-size: 1.4em;
+}
+
+.header .nav.navbar-nav .not-link {
+    padding: 15px;
+    display: inline-block;
+}
+
+.nav > li {
+    > a {
+        color: $navbar-default-link-color
+    }
+    > a:hover {
+        color: $link-hover-color
+    }
+    > a.active {
+        color: $link-color
+    }
+}
+
+.theme-line header .navbar-nav a {
+    line-height: 25px;
+    font-size: 18px;
+}
+
+.theme-line .section-right {
+    padding-left: 30px;
+}
+
+.body-overlap .main-content {
+    margin-top: 30px;
+}
+
+.body-box .main-content,
+.body-overlap .main-content {
+    padding: 30px;
+    box-shadow: 0 0 0 1px $ignite-border-color;
+    background-color: $ignite-background-color;
+}
+
+body {
+    font-weight: 400;
+}
+
+h1, h2, h3, h4, h5, h6 {
+    font-weight: 700;
+    margin-bottom: 10px;
+}
+
+.container-footer {
+    margin-top: 20px;
+    margin-bottom: 20px;
+
+    p {
+        font-size: 12px;
+        margin-bottom: 0;
+    }
+}
+
+/* Modal */
+.modal {
+    display: block;
+    overflow: hidden;
+}
+
+.modal .close {
+    position: absolute;
+    top: 10px;
+    right: 10px;
+    float: none;
+}
+
+.modal-header {
+    border-top-left-radius: 6px;
+    border-top-right-radius: 6px;
+}
+
+// Close icon
+.modal-header .close {
+    margin-right: -2px;
+}
+
+.modal .modal-dialog {
+    width: 650px;
+}
+
+.modal .modal-content {
+    background-color: $gray-lighter;
+
+    .input-tip {
+        padding-top: 1px;
+    }
+}
+
+.modal .modal-content .modal-header {
+    background-color: $ignite-background-color;
+    text-align: center;
+    color: $ignite-header-color;
+    padding: 15px 25px 15px 15px;
+}
+
+.modal .modal-content .modal-header h4 {
+    font-size: 22px;
+}
+
+.modal .modal-content .modal-footer {
+    margin-top: 0;
+}
+
+.modal-footer {
+    label {
+        float: left;
+        margin: 0;
+    }
+
+    .btn:last-child {
+        margin-right: 0;
+    }
+
+    .checkbox {
+        margin: 0;
+    }
+}
+
+.login-header {
+    margin-top: 0;
+    margin-bottom: 20px;
+    font-size: 2em;
+}
+
+.login-footer {
+    @extend .modal-footer;
+
+    padding-left: 0;
+    padding-right: 0;
+
+    .btn {
+        margin-right: 0;
+    }
+}
+
+.modal-body {
+    margin-left: 20px;
+    margin-right: 20px;
+}
+
+.modal-body-with-scroll {
+    max-height: 420px;
+    overflow-y: auto;
+    margin: 0;
+}
+
+.greedy {
+    min-height: 100%;
+    height: #{"calc(100vh - 270px)"};
+}
+
+.signin-greedy {
+    height: #{"calc(100vh - 300px)"};
+}
+
+@media (min-width: 768px) {
+    .navbar-nav > li > a {
+        padding: 0 15px;
+    }
+}
+
+.details-row {
+    padding: 0 5px;
+}
+
+.details-row, .settings-row {
+    display: block;
+    margin: 10px 0;
+
+    [class*="col-"] {
+        display: inline-block;
+        vertical-align: middle;
+        float: none;
+    }
+
+    input[type="checkbox"] {
+        line-height: 20px;
+        margin-right: 5px;
+    }
+
+    .checkbox label {
+        line-height: 20px !important;
+        vertical-align: middle;
+    }
+}
+
+.group-section {
+    margin-top: 20px;
+}
+
+.details-row:first-child {
+    margin-top: 0;
+
+    .group-section {
+        margin-top: 10px;
+    }
+}
+
+.details-row:last-child {
+    margin-bottom: 0;
+}
+
+.settings-row:first-child {
+    margin-top: 0;
+
+    .group-section {
+        margin-top: 0;
+    }
+}
+
+.settings-row:last-child {
+    margin-bottom: 0;
+}
+
+button, .btn {
+    margin-right: 5px;
+}
+
+i.btn {
+    margin-right: 0;
+}
+
+.btn {
+    padding: 3px 6px;
+
+    :focus {
+        //outline: none;
+        //border: 1px solid $btn-default-border;
+    }
+}
+
+.btn-group.pull-right {
+    margin-right: 0;
+}
+
+.btn-group {
+    margin-right: 5px;
+
+    > button, a.btn {
+        margin-right: 0;
+    }
+
+    button.btn + .btn {
+        margin-left: 0;
+    }
+
+    > .btn + .dropdown-toggle {
+        margin-right: 0;
+        padding: 3px 6px;
+        border-left-width: 0;
+    }
+}
+
+h1,
+h2,
+h3 {
+    user-select: none;
+    font-weight: normal;
+    /* Makes the vertical size of the text the same for all fonts. */
+    line-height: 1;
+}
+
+h3 {
+    font-size: 1.2em;
+    margin-top: 0;
+    margin-bottom: 1.5em;
+}
+
+.base-control {
+    text-align: left;
+    padding: 3px 3px;
+    height: $input-height;
+}
+
+.sql-name-input {
+    @extend .form-control;
+
+    width: auto;
+}
+
+.form-control {
+    @extend .base-control;
+
+    display: inline-block;
+
+    button {
+        text-align: left;
+    }
+}
+
+button.form-control {
+    display: block;
+    overflow: hidden;
+    white-space: nowrap;
+    text-overflow: ellipsis;
+}
+
+.theme-line .notebook-header {
+    border-color: $gray-lighter;
+
+    h1 {
+        padding: 0;
+        margin: 0;
+
+        height: 40px;
+
+        label {
+            overflow: hidden;
+            text-overflow: ellipsis;
+            white-space: nowrap;
+            margin-top: 5px;
+        }
+
+        .btn-group {
+            margin-top: -5px;
+            margin-left: 5px;
+        }
+
+        > i.btn {
+            float: right;
+            line-height: 30px;
+        }
+
+        input {
+            font-size: 22px;
+            height: 35px;
+        }
+
+        a.dropdown-toggle {
+            font-size: $font-size-base;
+            margin-right: 5px;
+        }
+    }
+}
+
+.theme-line .paragraphs {
+    .panel-group .panel + .panel {
+        margin-top: 30px;
+    }
+
+    .btn-group {
+        margin-right: 0;
+    }
+
+    .sql-editor {
+        padding: 5px 0;
+
+        .ace_cursor {
+            opacity: 1;
+        }
+
+        .ace_hidden-cursors {
+            opacity: 1;
+        }
+
+        .ace_gutter-cell, .ace_folding-enabled > .ace_gutter-cell {
+            padding-right: 5px;
+        }
+    }
+
+    table thead {
+        background-color: white;
+    }
+
+    .wrong-caches-filter {
+        text-align: center;
+        color: $ignite-placeholder-color;
+        height: 65px;
+        line-height: 65px;
+    }
+
+    .empty-caches {
+        text-align: center;
+        color: $ignite-placeholder-color;
+        height: 55px;
+        line-height: 55px;
+    }
+
+    .sql-controls {
+        border-top: 1px solid $ignite-border-color;
+
+        padding: 10px 10px;
+    }
+
+    .sql-result {
+        border-top: 1px solid $ignite-border-color;
+
+        .error {
+            padding: 10px 10px;
+
+            text-align: center;
+            color: $brand-primary;
+        }
+
+        .empty {
+            padding: 10px 10px;
+
+            text-align: center;
+            color: $ignite-placeholder-color;
+        }
+
+        .total {
+            padding: 10px 10px;
+        }
+
+        .table {
+            margin: 0
+        }
+
+        .chart {
+            margin: 0
+        }
+
+        .footer {
+            border-top: 1px solid $ignite-border-color;
+
+            padding: 5px 10px;
+        }
+    }
+}
+
+.theme-line .panel-heading {
+    padding: 5px 10px;
+    margin: 0;
+    cursor: pointer;
+    font-size: $font-size-large;
+    line-height: 24px;
+
+    label {
+        overflow: hidden;
+        text-overflow: ellipsis;
+        white-space: nowrap;
+        max-width: calc(100% - 85px);
+        cursor: pointer;
+    }
+
+    .btn-group {
+        vertical-align:top;
+        margin-left: 10px;
+
+        i { line-height: 18px; }
+    }
+
+    > i {
+        vertical-align: top;
+        line-height: 26px;
+        height: 26px;
+    }
+
+    .fa {
+        line-height: 26px;
+    }
+
+    .fa-floppy-o {
+        float: right;
+    }
+
+    .fa-chevron-circle-right, .fa-chevron-circle-down {
+        font-size: $font-size-base;
+        color: inherit;
+        float: left;
+    }
+
+    .fa-undo {
+        padding: 1px 6px;
+
+        font-size: 16px;
+    }
+
+    .fa-undo:hover {
+        padding: 0 5px;
+
+        border-radius: 5px;
+        border: thin dotted $ignite-darck-border-color;
+    }
+}
+
+.theme-line .panel-heading:hover {
+    text-decoration: underline;
+}
+
+.theme-line .panel-body {
+    padding: 20px;
+}
+
+.theme-line .main-content a.customize {
+    margin-left: 5px;
+}
+
+.theme-line .panel-collapse {
+    margin: 0;
+}
+
+.theme-line table.links {
+    table-layout: fixed;
+    border-collapse: collapse;
+
+    width: 100%;
+
+    label.placeholder {
+        text-align: center;
+        color: $ignite-placeholder-color;
+        width: 100%;
+    }
+
+    input[type="text"] {
+        font-weight: normal;
+    }
+
+    input[type="radio"] {
+        margin-left: 1px;
+        margin-right: 5px;
+    }
+
+    tbody {
+        border-left: 10px solid transparent;
+    }
+
+    tbody td:first-child {
+        overflow: hidden;
+        text-overflow: ellipsis;
+        white-space: nowrap;
+    }
+
+    tfoot > tr > td {
+        padding: 0;
+
+        .pagination {
+            margin: 10px 0;
+
+            > .active > a {
+                border-color: $table-border-color;
+                background-color: $gray-lighter;
+            }
+        }
+    }
+}
+
+.theme-line table.links-edit {
+    @extend table.links;
+
+    margin-top: 0;
+    margin-bottom: 5px;
+
+    label {
+        line-height: $input-height;
+    }
+
+    td {
+        padding-left: 0;
+    }
+}
+
+.theme-line table.links-edit-sub {
+    @extend table.links-edit;
+
+    margin-top: 0;
+    margin-bottom: 0;
+}
+
+.theme-line table.links-edit-details {
+    @extend table.links;
+
+    margin-bottom: 10px;
+
+    label {
+        line-height: $input-height;
+        color: $ignite-header-color;
+    }
+
+    td {
+        padding: 0;
+
+        .input-tip {
+            padding: 0;
+        }
+    }
+}
+
+.theme-line table.admin {
+    tr:hover {
+        cursor: default;
+    }
+
+    thead {
+        .pagination {
+            margin: 0;
+        }
+    }
+
+    thead > tr th.header {
+        padding: 0 0 10px;
+
+        div {
+            padding: 0;
+        }
+
+        input[type="text"] {
+            font-weight: normal;
+        }
+    }
+
+    margin-bottom: 10px;
+
+    label {
+        line-height: $input-height;
+        color: $ignite-header-color;
+    }
+
+    thead > tr th, td {
+        padding: 10px 10px;
+
+        .input-tip {
+            padding: 0;
+        }
+    }
+
+    tfoot > tr > td {
+        padding: 0;
+    }
+
+    .pagination {
+        margin: 10px 0;
+        font-weight: normal;
+
+        > .active > a {
+            border-color: $table-border-color;
+            background-color: $gray-lighter;
+        }
+    }
+}
+
+.admin-summary {
+    padding-bottom: 10px;
+}
+
+.import-domain-model-wizard-page {
+    margin: 15px;
+}
+
+.scrollable-y {
+    overflow-x: hidden;
+    overflow-y: auto;
+}
+
+.theme-line table.metadata {
+    margin-bottom: 10px;
+
+    tr:hover {
+        cursor: default;
+    }
+
+    thead > tr {
+        label {
+            font-weight: bold;
+        }
+
+        input[type="checkbox"] {
+            cursor: pointer;
+        }
+    }
+
+    thead > tr th.header {
+        padding: 0 0 10px;
+
+        .pull-right {
+            padding: 0;
+        }
+
+        input[type="checkbox"] {
+            cursor: pointer;
+        }
+
+        input[type="text"] {
+            font-weight: normal;
+        }
+    }
+
+    > thead > tr > th {
+        padding: 5px 0 5px 5px !important;
+    }
+
+    tbody > tr > td {
+        padding: 0;
+    }
+}
+
+.td-ellipsis {
+    overflow: hidden;
+    text-overflow: ellipsis;
+    white-space: nowrap;
+}
+
+.table-modal-striped {
+    width: 100%;
+
+    > tbody > tr {
+        border-bottom: 2px solid $ignite-border-color;
+
+        input[type="checkbox"] {
+            cursor: pointer;
+        }
+    }
+
+    > tbody > tr > td {
+        padding: 5px 0 5px 5px !important;
+    }
+}
+
+.theme-line table.sql-results {
+    margin: 0;
+
+    td {
+        padding: 3px 6px;
+    }
+
+    > thead > tr > td {
+        padding: 3px 0;
+    }
+
+    thead > tr > th {
+        padding: 3px 6px;
+
+        line-height: $input-height;
+    }
+
+    tfoot > tr > td {
+        padding: 0;
+
+        .pagination {
+            margin: 10px 0 0 0;
+
+            > .active > a {
+                border-color: $table-border-color;
+                background-color: $gray-lighter;
+            }
+        }
+    }
+}
+
+.affix {
+    z-index: 910;
+    background-color: white;
+
+    hr {
+        margin: 0;
+    }
+}
+
+.affix.padding-top-dflt {
+    hr {
+        margin-top: 10px;
+    }
+}
+
+.affix + .bs-affix-fix {
+    height: 78px;
+}
+
+.panel-details {
+    margin-top: 5px;
+    padding: 10px 5px;
+
+    border-radius: 5px;
+    border: thin dotted $ignite-border-color;
+}
+
+.panel-details-noborder {
+    margin-top: 5px;
+    padding: 10px 5px;
+}
+
+.group {
+    border-radius: 5px;
+    border: thin dotted $ignite-border-color;
+
+    text-align: left;
+
+    hr {
+        margin: 7px 0;
+    }
+}
+
+.group-legend {
+    margin: -10px 5px 0 10px;
+    overflow: visible;
+    position: relative;
+
+    label {
+        padding: 0 5px;
+        background: white;
+    }
+}
+
+.group-legend-btn {
+    background: white;
+    float: right;
+    line-height: 20px;
+    padding: 0 5px 0 5px;
+}
+
+.group-content {
+    margin: 10px;
+
+    table {
+        width: 100%;
+    }
+}
+
+.group-content-empty {
+    color: $input-color-placeholder;
+
+    padding: 10px 0;
+    position: relative;
+
+    text-align: center;
+}
+
+.content-not-available {
+    min-height: 28px;
+
+    margin-right: 20px;
+
+    border-radius: 5px;
+    border: thin dotted $ignite-border-color;
+
+    padding: 0;
+
+    color: $input-color-placeholder;
+    display: table;
+    width: 100%;
+    height: 26px;
+
+    label {
+        display: table-cell;
+        text-align: center;
+        vertical-align: middle;
+    }
+}
+
+.tooltip > .tooltip-inner {
+    text-align: left;
+    border: solid 1px #ccc;
+}
+
+.popover-footer {
+    margin: 0; // reset heading margin
+    padding: 8px 14px;
+    font-size: $font-size-base;
+    color: $input-color-placeholder;
+    background-color: $popover-title-bg;
+    border-top: 1px solid darken($popover-title-bg, 5%);
+    border-radius: 0 0 ($border-radius-large - 1) ($border-radius-large - 1);
+}
+
+.popover-content {
+    padding: 5px;
+}
+
+.popover:focus {
+    outline: none;
+    border: 1px solid $btn-default-border;
+}
+
+.theme-line .popover.settings {
+    .close {
+        position: absolute;
+        top: 5px;
+        right: 5px;
+    }
+}
+
+.theme-line .popover.cache-metadata {
+    @extend .popover.settings;
+
+    position: absolute;
+    z-index: 1030;
+    min-width: 305px;
+    max-width: 450px;
+
+    .popover-title {
+        color: black;
+
+        line-height: 27px;
+
+        padding: 3px 5px 3px 10px;
+
+        white-space: nowrap;
+        overflow: hidden;
+        -o-text-overflow: ellipsis;
+        text-overflow: ellipsis;
+
+        .close {
+            float: right;
+            top: 0;
+            right: 0;
+            position: relative;
+            margin-left: 10px;
+            line-height: 27px;
+        }
+    }
+
+    > .popover-content {
+        overflow: auto;
+
+        white-space: nowrap;
+
+        min-height: 400px;
+        max-height: 400px;
+
+        .content-empty {
+            display: block;
+            text-align: center;
+            line-height: 380px;
+
+            color: $input-color-placeholder;
+        }
+    }
+
+    .clickable { cursor: pointer; }
+}
+
+.theme-line .popover.summary-project-structure {
+    @extend .popover.settings;
+
+    z-index: 1030;
+    min-width: 305px;
+
+    .popover-title {
+        color: black;
+
+        line-height: 27px;
+
+        padding: 3px 5px 3px 10px;
+
+        white-space: nowrap;
+        overflow: hidden;
+        -o-text-overflow: ellipsis;
+        text-overflow: ellipsis;
+
+        .close {
+            float: right;
+            top: 0;
+            right: 0;
+            position: relative;
+            margin-left: 10px;
+            line-height: 27px;
+        }
+    }
+
+    > .popover-content {
+        overflow: auto;
+
+        white-space: nowrap;
+
+        min-height: 300px;
+        max-height: 300px;
+    }
+}
+
+.theme-line .popover.validation-error {
+    max-width: 400px;
+    color: $brand-primary;
+    background: white;
+    border: 1px solid $brand-primary;
+
+    &.right > .arrow {
+        border-right-color: $brand-primary;
+    }
+
+    .close {
+        vertical-align: middle;
+    }
+}
+
+label {
+    font-weight: normal;
+    margin-bottom: 0;
+}
+
+.form-horizontal .checkbox {
+    padding-top: 0;
+    min-height: 0;
+}
+
+.input-tip {
+    display: block;
+    overflow: hidden;
+    position: relative;
+}
+
+.labelHeader {
+    font-weight: bold;
+    text-transform: capitalize;
+}
+
+.labelField {
+    float: left;
+    margin-right: 5px;
+}
+
+.labelFormField {
+    float: left;
+    line-height: $input-height;
+}
+
+.labelLogin {
+    margin-right: 10px;
+}
+
+.form-horizontal .form-group {
+    margin: 0;
+}
+
+.form-horizontal .has-feedback .form-control-feedback {
+    right: 0;
+}
+
+.tipField {
+    float: right;
+    line-height: $input-height;
+    margin-left: 5px;
+}
+
+.tipLabel {
+    font-size: $font-size-base;
+    margin-left: 5px;
+}
+
+.fieldSep {
+    float: right;
+    line-height: $input-height;
+    margin: 0 5px;
+}
+
+.fieldButton {
+    float: right;
+    margin-left: 5px;
+    margin-right: 0;
+}
+
+.fa {
+    cursor: pointer;
+}
+
+.fa-cursor-default {
+    cursor: default !important;
+}
+
+.fa-remove {
+    color: $brand-primary;
+}
+
+.fa-chevron-circle-down {
+    color: $brand-primary;
+    margin-right: 5px;
+}
+
+.fa-chevron-circle-right {
+    color: $brand-primary;
+    margin-right: 5px;
+}
+
+.fa-question-circle {
+    cursor: default;
+}
+
+label.required:after {
+    color: $brand-primary;
+    content: ' *';
+    display: inline;
+}
+
+.blank {
+    visibility: hidden;
+}
+
+.alert {
+    outline: 0;
+    padding: 10px;
+    position: fixed;
+    z-index: 1050;
+    margin: 20px;
+    max-width: 700px;
+
+    &.top-right {
+        top: 60px;
+        right: 0;
+
+        .close {
+            padding-left: 10px;
+        }
+    }
+
+    .alert-icon {
+        padding-right: 10px;
+        font-size: 16px;
+    }
+
+    .alert-title {
+        color: $text-color;
+    }
+
+    .close {
+        margin-right: 0;
+        line-height: 19px;
+    }
+}
+
+.summary-tabs {
+    margin-top: 0.65em;
+}
+
+.summary-tab {
+    img {
+        margin-right: 5px;
+        height: 16px;
+        width: 16px;
+        float: left;
+    }
+}
+
+input[type="number"]::-webkit-outer-spin-button,
+input[type="number"]::-webkit-inner-spin-button {
+    -webkit-appearance: none;
+    margin: 0;
+}
+
+input[type="number"] {
+    -moz-appearance: textfield;
+}
+
+input.ng-dirty.ng-invalid, button.ng-dirty.ng-invalid {
+    border-color: $ignite-invalid-color;
+
+    :focus {
+        border-color: $ignite-invalid-color;
+    }
+}
+
+.form-control-feedback {
+    display: inline-block;
+    color: $brand-primary;
+    line-height: $input-height;
+    pointer-events: initial;
+}
+
+.theme-line .nav-tabs > li > a {
+    padding: 5px 5px;
+    color: $ignite-header-color;
+}
+
+.viewedUser {
+    text-align: center;
+    background-color: $brand-warning;
+}
+
+a {
+    cursor: pointer;
+}
+
+.st-sort-ascent:after {
+    content: '\25B2';
+}
+
+.st-sort-descent:after {
+    content: '\25BC';
+}
+
+th[st-sort] {
+    cursor: pointer;
+}
+
+.panel {
+    margin-bottom: 0;
+}
+
+.panel-group {
+    margin-bottom: 0;
+}
+
+.panel-group .panel + .panel {
+    margin-top: 20px;
+}
+
+.section {
+    margin-top: 20px;
+}
+
+.section-top {
+    width: 100%;
+    margin-top: 10px;
+    margin-bottom: 20px;
+}
+
+.advanced-options {
+    @extend .section;
+    margin-bottom: 20px;
+
+    i {
+        font-size: 16px;
+    }
+}
+
+.modal-advanced-options {
+    @extend .advanced-options;
+    margin-top: 10px;
+    margin-bottom: 10px;
+}
+
+.margin-left-dflt {
+    margin-left: 10px;
+}
+
+.margin-top-dflt {
+    margin-top: 10px;
+}
+
+.margin-top-dflt-2x {
+    margin-top: 20px;
+}
+
+.margin-bottom-dflt {
+    margin-bottom: 10px;
+}
+
+.margin-dflt {
+    margin-top: 10px;
+    margin-bottom: 10px;
+}
+
+.padding-top-dflt {
+    padding-top: 10px;
+}
+
+.padding-left-dflt {
+    padding-left: 10px;
+}
+
+.padding-bottom-dflt {
+    padding-bottom: 10px;
+}
+
+.padding-dflt {
+    padding-top: 10px;
+    padding-bottom: 10px;
+}
+
+.agent-download {
+    padding: 10px 10px 10px 20px;
+}
+
+.ace_content {
+    padding-left: 5px;
+}
+
+.ace_hidden-cursors {
+    opacity: 0;
+}
+
+.ace_cursor {
+    opacity: 0;
+}
+
+.ace_editor {
+    margin: 10px 5px 10px 0;
+
+    .ace_gutter {
+        background: transparent !important;
+        border: 1px $ignite-border-color;
+        border-right-style: solid;
+    }
+
+    .ace_gutter-cell, .ace_folding-enabled > .ace_gutter-cell {
+        padding-left: 0.65em;
+    }
+}
+
+.preview-highlight-1 {
+    position: absolute;
+    background-color: #f7faff;
+    z-index: 20;
+}
+
+.preview-highlight-2 {
+    position: absolute;
+    background-color: #f0f6ff;
+    z-index: 21;
+}
+
+.preview-highlight-3 {
+    position: absolute;
+    background-color: #e8f2ff;
+    z-index: 22;
+}
+
+.preview-highlight-4 {
+    position: absolute;
+    background-color: #e1eeff;
+    z-index: 23;
+}
+
+.preview-highlight-5 {
+    position: absolute;
+    background-color: #DAEAFF;
+    z-index: 24;
+}
+
+.preview-highlight-6 {
+    position: absolute;
+    background-color: #D2E5FF;
+    z-index: 25;
+}
+
+.preview-highlight-7 {
+    position: absolute;
+    background-color: #CBE1FF;
+    z-index: 26;
+}
+
+.preview-highlight-8 {
+    position: absolute;
+    background-color: #C3DDFF;
+    z-index: 27;
+}
+
+.preview-highlight-9 {
+    position: absolute;
+    background-color: #BCD9FF;
+    z-index: 28;
+}
+
+.preview-highlight-10 {
+    position: absolute;
+    background-color: #B5D5FF;
+    z-index: 29;
+}
+
+.preview-panel {
+    min-height: 28px;
+
+    margin-left: 20px;
+
+    border-radius: 5px;
+    border: thin dotted $ignite-border-color;
+
+    padding: 0;
+}
+
+.preview-legend {
+    top: -10px;
+    right: 20px;
+    position: absolute;
+    z-index: 900;
+
+    a {
+        background-color: white;
+        margin-left: 5px;
+        font-size: 0.9em;
+    }
+
+    .inactive {
+        color: $input-color-placeholder;
+    }
+}
+
+.preview-content-empty {
+    color: $input-color-placeholder;
+    display: table;
+    width: 100%;
+    height: 26px;
+
+    label {
+        display: table-cell;
+        text-align: center;
+        vertical-align: middle;
+    }
+}
+
+.chart-settings-link {
+    padding-left: 10px;
+    line-height: $input-height;
+
+    label, button {
+        margin-left: 5px;
+        margin-right: 0;
+    }
+
+    button.select-manual-caret {
+        padding-right: 3px;
+
+        .caret { margin-left: 3px; }
+    }
+
+    a, i {
+        font-size: $font-size-base;
+        color: $link-color !important;
+        margin-right: 5px;
+    }
+
+    div {
+        margin-left: 20px;
+        display: inline-block;
+    }
+}
+
+.chart-settings {
+    margin: 10px 5px 5px 5px !important;
+}
+
+.chart-settings-columns-list {
+    border: 1px solid $ignite-border-color;
+    list-style: none;
+    margin-bottom: 10px;
+    min-height: 30px;
+    max-height: 200px;
+    padding: 5px;
+
+    overflow: auto;
+
+    & > li {
+        float: left;
+    }
+
+    li:nth-child(even) {
+        margin-right: 0;
+    }
+
+    .fa-close {
+        margin-left: 10px;
+    }
+}
+
+.btn-chart-column {
+    border-radius: 3px;
+    font-size: 12px;
+    margin: 3px 3px;
+    padding: 1px 5px;
+    line-height: 1.5;
+    cursor: default;
+}
+
+.btn-chart-column-movable {
+    @extend .btn-chart-column;
+    cursor: move;
+}
+
+.btn-chart-column-agg-fx {
+    border: 0;
+    margin: 0 0 0 10px;
+}
+
+.dw-loading {
+    min-height: 100px;
+}
+
+.dw-loading > .dw-loading-body > .dw-loading-text {
+    left: -50%;
+}
+
+.dw-loading.dw-loading-overlay {
+    z-index: 1030;
+}
+
+.modal {
+    .dw-loading.dw-loading-overlay {
+        z-index: 9999;
+    }
+
+    .dw-loading-body {
+        left: 10%;
+    }
+}
+
+.panel-tip-container {
+    display: inline-block;
+}
+
+button.dropdown-toggle {
+    margin-right: 5px;
+}
+
+button.select-toggle {
+    position: relative;
+    padding-right: 15px;
+}
+
+button.select-toggle::after {
+    content: "";
+    border-top: 0.3em solid;
+    border-right: 0.3em solid transparent;
+    border-left: 0.3em solid transparent;
+    position: absolute;
+    right: 5px;
+    top: 50%;
+    vertical-align: middle;
+}
+
+// Prevent scroll bars from being hidden for OS X.
+::-webkit-scrollbar {
+    -webkit-appearance: none;
+}
+
+::-webkit-scrollbar:vertical {
+    width: 10px;
+}
+
+::-webkit-scrollbar:horizontal {
+    height: 10px;
+}
+
+::-webkit-scrollbar-thumb {
+    border-radius: 8px;
+    border: 2px solid white; /* should match background, can't be transparent */
+    background-color: rgba(0, 0, 0, .5);
+}
+
+::-webkit-scrollbar-track {
+    background-color: white;
+    border-radius: 8px;
+}
+
+treecontrol.tree-classic {
+    > ul > li {
+        padding: 0;
+    }
+
+    li {
+        padding-left: 15px;
+    }
+
+    li.tree-expanded i.tree-branch-head.fa, li.tree-collapsed i.tree-branch-head.fa, li.tree-leaf i.tree-branch-head.fa, .tree-label i.fa {
+        background: none no-repeat;
+        padding: 1px 5px 1px 1px;
+    }
+
+    li.tree-leaf i.tree-leaf-head {
+        background: none no-repeat !important;
+        padding: 0 !important;
+    }
+
+    li .tree-selected {
+        background-color: white;
+        font-weight: normal;
+    }
+
+    span {
+        margin-right: 10px;
+    }
+}
+
+.docs-content {
+    .affix {
+        border-bottom: 1px solid $gray-lighter;
+    }
+
+    min-height: 100px;
+}
+
+.carousel-caption {
+    position: relative;
+    left: auto;
+    right: auto;
+
+    margin-top: 10px;
+
+    h3 {
+        margin-bottom: 10px;
+    }
+}
+
+.carousel-control {
+    font-size: 20px;
+    z-index: 16;
+
+    // Toggles
+    .fa-chevron-left,.fa-chevron-right {
+        position: absolute;
+        bottom: 28px;
+        margin-top: -10px;
+        z-index: 16;
+        display: inline-block;
+        margin-left: -10px;
+    }
+
+    .fa-chevron-left {
+        left: 90%;
+        margin-left: -10px;
+    }
+
+    .fa-chevron-right {
+        right: 90%;
+        margin-right: -10px;
+    }
+}
+
+.carousel-control.left {
+    background-image: none;
+}
+
+.carousel-control.right {
+    background-image: none;
+}
+
+.getting-started-puzzle {
+    margin-left: 20px;
+}
+
+.getting-started {
+    margin: 15px 15px 300px;
+}
+
+.getting-started-demo {
+    color: $brand-info;
+}
+
+.home-panel {
+    border-radius: 5px;
+    border: thin dotted $panel-default-border;
+    background-color: $panel-default-heading-bg;
+
+    margin-top: 20px;
+    padding: 10px;
+}
+
+.home {
+    min-height: 880px;
+    padding: 20px;
+
+    @media(min-width: 992px) {
+        min-height: 450px;
+    }
+}
+
+.additional-filter {
+    input[type="checkbox"] {
+        position: absolute;
+        margin-top: 8px;
+    }
+
+    a {
+        font-weight: normal;
+        padding-left: 20px;
+        float: none;
+    }
+}
+
+.grid {
+    .ui-grid-header-cell .ui-grid-cell-contents {
+        text-align: center;
+
+        > span:not(.ui-grid-header-cell-label) {
+            position: absolute;
+            right: -3px;
+        }
+    }
+
+    .ui-grid-cell .ui-grid-cell-contents {
+        text-align: center;
+        white-space: pre;
+
+        > i.fa {
+            cursor: default;
+        }
+    }
+
+    .ui-grid-column-menu-button {
+        right: -3px;
+    }
+
+    .ui-grid-menu-button {
+        margin-top: -1px;
+    }
+
+    .ui-grid-column-menu-button-last-col {
+        margin-right: 0
+    }
+
+    .no-rows {
+        .center-container {
+            background: white;
+
+            .centered > div {
+                display: inline-block;
+                padding: 10px;
+
+                opacity: 1;
+
+                background-color: #f5f5f5;
+                border-radius: 6px;
+                border: 1px solid $ignite-darck-border-color;
+            }
+        }
+    }
+}
+
+.cell-right .ui-grid-cell-contents {
+    text-align: right !important;
+}
+
+.cell-left .ui-grid-cell-contents {
+    text-align: left !important;
+}
+
+.grid.ui-grid {
+    border-left-width: 0;
+    border-right-width: 0;
+    border-bottom-width: 0;
+}
+
+.summary-tabs {
+    .nav-tabs > li:first-child,
+    .nav-tabs > li:first-child.active {
+        & > a,
+        & > a:focus,
+        & > a:hover {
+            border-left: none;
+            border-top-left-radius: 0;
+        }
+    }
+}
+
+.ribbon-wrapper {
+    width: 150px;
+    height: 150px;
+    position: absolute;
+    overflow: hidden;
+    top: 0;
+    z-index: 1001;
+    pointer-events: none;
+}
+
+.ribbon-wrapper.right {
+    right: 0;
+}
+
+.ribbon {
+    position: absolute;
+    top: 42px;
+    width: 200px;
+    padding: 1px 0;
+    color: $btn-primary-color;
+    background: $btn-primary-border;
+
+    -moz-box-shadow: 0 0 10px rgba(0,0,0,0.5);
+    -webkit-box-shadow: 0 0 10px rgba(0,0,0,0.5);
+    box-shadow: 0 0 10px rgba(0,0,0,0.5);
+
+    right: -42px;
+    -moz-transform: rotate(45deg);
+    -webkit-transform: rotate(45deg);
+    -o-transform: rotate(45deg);
+    -ms-transform: rotate(45deg);
+    transform: rotate(45deg);
+
+    > label {
+        display: block;
+        padding: 1px 0;
+        height: 24px;
+        line-height: 18px;
+
+        text-align: center;
+        text-decoration: none;
+        font-family: $font-family-sans-serif;
+        font-size: 20px;
+        font-weight: 500;
+
+        border: 1px solid rgba(255,255,255,0.3);
+
+        -moz-text-shadow: 0 0 10px rgba(0,0,0,0.31);
+        -webkit-text-shadow: 0 0 10px rgba(0,0,0,0.31);
+        text-shadow: 0 0 10px rgba(0,0,0,0.31);
+    }
+}
+
+html,body,.splash-screen {
+    width: 100%;
+    height: 100%;
+}
+
+.splash {
+    position: fixed;
+    bottom: 0;
+    left: 0;
+    right: 0;
+    top: 0;
+    opacity: 1;
+    background-color: white;
+    z-index: 99999;
+
+    .splash-wrapper {
+        display: inline-block;
+        vertical-align: middle;
+        position: relative;
+        width: 100%;
+    }
+
+    .splash-wellcome {
+        font-size: 18px;
+        margin: 20px 0;
+        text-align: center;
+    }
+}
+
+.splash:before {
+  content: '';
+  display: inline-block;
+  height: 100%;
+  vertical-align: middle;
+}
+
+.spinner {
+    margin: 0 auto;
+    width: 100px;
+    text-align: center;
+
+    > div {
+        width: 18px;
+        height: 18px;
+        margin: 0 5px;
+        border-radius: 100%;
+        display: inline-block;
+        -webkit-animation: sk-bouncedelay 1.4s infinite ease-in-out both;
+        animation: sk-bouncedelay 1.4s infinite ease-in-out both;
+        background-color: $brand-primary;
+    }
+
+    .bounce1 {
+        -webkit-animation-delay: -0.32s;
+        animation-delay: -0.32s;
+    }
+
+    .bounce2 {
+        -webkit-animation-delay: -0.16s;
+        animation-delay: -0.16s;
+    }
+}
+
+@-webkit-keyframes sk-bouncedelay {
+    0%, 80%, 100% {
+        -webkit-transform: scale(0)
+    }
+    40% {
+        -webkit-transform: scale(1.0)
+    }
+}
+
+@keyframes sk-bouncedelay {
+    0%, 80%, 100% {
+        -webkit-transform: scale(0);
+        transform: scale(0);
+    }
+    40% {
+        -webkit-transform: scale(1.0);
+        transform: scale(1.0);
+    }
+}
+
+[ng\:cloak], [ng-cloak], [data-ng-cloak], [x-ng-cloak], .ng-cloak, .x-ng-cloak {
+    display: none !important;
+}
+
+.nvd3 .nv-axis .nv-axisMaxMin text {
+    font-weight: normal; /* Here the text can be modified*/
+}
+
+[ng-hide].ng-hide-add.ng-hide-animate {
+    display: none;
+}
+
+[ng-show].ng-hide-add.ng-hide-animate {
+    display: none;
+}
+
+@media only screen and (max-width: 767px) {
+    .container{
+        padding: 0 $padding-small-horizontal;
+    }
+}
+
+.domains-import-dialog {
+    .modal-body {
+        height: 325px;
+        margin: 0;
+        padding: 0;
+    }
+}

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/frontend/public/stylesheets/variables.scss
----------------------------------------------------------------------
diff --git a/modules/web-console/frontend/public/stylesheets/variables.scss b/modules/web-console/frontend/public/stylesheets/variables.scss
new file mode 100644
index 0000000..8500eac
--- /dev/null
+++ b/modules/web-console/frontend/public/stylesheets/variables.scss
@@ -0,0 +1,28 @@
+/*
+ * 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 "bootstrap-variables";
+
+$logo-path: "/images/logo.png";
+$input-height: 28px;
+$ignite-placeholder-color: #999999;
+$ignite-border-color: #ddd;
+$ignite-darck-border-color: #aaa;
+$ignite-border-bottom-color: $brand-primary;
+$ignite-background-color: #fff;
+$ignite-header-color: #555;
+$ignite-invalid-color: $brand-primary;

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/frontend/test/e2e/exampe.test.js
----------------------------------------------------------------------
diff --git a/modules/web-console/frontend/test/e2e/exampe.test.js b/modules/web-console/frontend/test/e2e/exampe.test.js
new file mode 100644
index 0000000..c778c79
--- /dev/null
+++ b/modules/web-console/frontend/test/e2e/exampe.test.js
@@ -0,0 +1,40 @@
+/*
+ * 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.
+ */
+
+suite('ExampleTestSuite', () => {
+    setup(() => {
+        // browser.get('http://localhost:9000/');
+    });
+
+    test('initially has a greeting', (done) => {
+        done();
+
+        // element(by.model('ui.email')).sendKeys('jhon@doe.com');
+    });
+
+    test('initially has a greeting', (done) => {
+        done();
+
+        // element(by.model('ui.email')).sendKeys('jhon@doe.com');
+    });
+
+    test('initially has a greeting', (done) => {
+        done();
+
+        // element(by.model('ui.email')).sendKeys('jhon@doe.com');
+    });
+});
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/frontend/test/karma.conf.js
----------------------------------------------------------------------
diff --git a/modules/web-console/frontend/test/karma.conf.js b/modules/web-console/frontend/test/karma.conf.js
new file mode 100644
index 0000000..e13ba00
--- /dev/null
+++ b/modules/web-console/frontend/test/karma.conf.js
@@ -0,0 +1,113 @@
+/*
+ * 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 path = require('path');
+const webpack = require('webpack');
+
+const basePath = path.resolve('./');
+
+module.exports = function(config) {
+    config.set({
+        // Base path that will be used to resolve all patterns (eg. files, exclude).
+        basePath: basePath,
+
+        // Frameworks to use available frameworks: https://npmjs.org/browse/keyword/karma-adapter
+        frameworks: ['mocha'],
+
+        // List of files / patterns to load in the browser.
+        files: [
+            'test/**/*.test.js'
+        ],
+
+        plugins: [
+            require('karma-phantomjs-launcher'),
+            require('karma-teamcity-reporter'),
+            require('karma-webpack'),
+            require('karma-mocha')
+        ],
+
+        // Preprocess matching files before serving them to the browser
+        // available preprocessors: https://npmjs.org/browse/keyword/karma-preprocessor.
+        preprocessors: {
+            'test/**/*.js': ['webpack']
+        },
+
+        webpack: {
+            module: {
+                loaders: [
+                    {
+                        test: /\.json$/,
+                        loader: 'json'
+                    },
+                    {
+                        test: /\.js$/,
+                        loader: 'babel',
+                        exclude: /node_modules/
+                    }
+                ]
+            },
+            resolve: {
+                extensions: ["", ".js"]
+            },
+            plugins: [
+                new webpack.ProvidePlugin({
+                    _: 'lodash'
+                })
+            ]
+        },
+
+        webpackMiddleware: {
+            noInfo: true
+        },
+
+        // Test results reporter to use
+        // possible values: 'dots', 'progress'
+        // available reporters: https://npmjs.org/browse/keyword/karma-reporter.
+        reporters: ['teamcity'],
+
+        // web server port
+        port: 9876,
+
+        // enable / disable colors in the output (reporters and logs)
+        colors: true,
+
+        // level of logging
+        // possible values: config.LOG_DISABLE || config.LOG_ERROR || config.LOG_WARN || config.LOG_INFO || config.LOG_DEBUG
+        logLevel: config.LOG_INFO,
+
+        // enable / disable watching file and executing tests whenever any file changes
+        autoWatch: true,
+
+        // start these browsers
+        // available browser launchers: https://npmjs.org/browse/keyword/karma-launcher
+        browsers: ['PhantomJS'],
+
+        // Continuous Integration mode
+        // if true, Karma captures browsers, runs the tests and exits
+        singleRun: true,
+
+        // Concurrency level
+        // how many browser should be started simultaneous
+        concurrency: Infinity,
+
+        client: {
+            mocha: {
+                ui: 'tdd'
+            }
+        }
+    });
+};

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/frontend/test/protractor.conf.js
----------------------------------------------------------------------
diff --git a/modules/web-console/frontend/test/protractor.conf.js b/modules/web-console/frontend/test/protractor.conf.js
new file mode 100644
index 0000000..3386e66
--- /dev/null
+++ b/modules/web-console/frontend/test/protractor.conf.js
@@ -0,0 +1,50 @@
+/*
+ * 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.
+ */
+
+// exports.config = {
+//   specs: ['test/e2e/*.js'],
+//   capabilities: {
+
+//   }
+// };
+
+exports.config = {
+  seleniumAddress: 'http://localhost:4444/wd/hub',
+
+  capabilities: {
+    'browserName': 'chrome'
+    // 'browserName': 'phantomjs',
+
+    // /*
+    //  * Can be used to specify the phantomjs binary path.
+    //  * This can generally be ommitted if you installed phantomjs globally.
+    //  */
+    // 'phantomjs.binary.path': require('phantomjs').path,
+
+    // /*
+    //  * Command line args to pass to ghostdriver, phantomjs's browser driver.
+    //  * See https://github.com/detro/ghostdriver#faq
+    //  */
+    // 'phantomjs.ghostdriver.cli.args': ['--loglevel=DEBUG']
+  },
+
+  specs: ['test/e2e/*.js'],
+
+  jasmineNodeOpts: {
+    showColors: true
+  }
+};

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/frontend/test/unit/JavaTypes.test.js
----------------------------------------------------------------------
diff --git a/modules/web-console/frontend/test/unit/JavaTypes.test.js b/modules/web-console/frontend/test/unit/JavaTypes.test.js
new file mode 100644
index 0000000..25c0f67
--- /dev/null
+++ b/modules/web-console/frontend/test/unit/JavaTypes.test.js
@@ -0,0 +1,69 @@
+/*
+ * 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 JavaTypes from '../../app/services/JavaTypes.service.js';
+
+import { assert } from 'chai';
+
+const { nonBuiltInClass, fullClassName, validIdentifier, validPackage, packageSpecified, isKeywords, isJavaPrimitive} = JavaTypes[1]();
+
+suite('JavaTypesTestsSuite', () => {
+    test('nonBuiltInClass', () => {
+        assert.equal(nonBuiltInClass('BigDecimal'), false);
+        assert.equal(nonBuiltInClass('java.math.BigDecimal'), false);
+
+        assert.equal(nonBuiltInClass('String'), false);
+        assert.equal(nonBuiltInClass('java.lang.String'), false);
+
+        assert.equal(nonBuiltInClass('Timestamp'), false);
+        assert.equal(nonBuiltInClass('java.sql.Timestamp'), false);
+
+        assert.equal(nonBuiltInClass('Date'), false);
+        assert.equal(nonBuiltInClass('java.sql.Date'), false);
+
+        assert.equal(nonBuiltInClass('Date'), false);
+        assert.equal(nonBuiltInClass('java.util.Date'), false);
+
+        assert.equal(nonBuiltInClass('CustomClass'), true);
+        assert.equal(nonBuiltInClass('java.util.CustomClass'), true);
+        assert.equal(nonBuiltInClass('my.package.CustomClass'), true);
+    });
+
+    test('fullClassName', () => {
+        assert.equal(fullClassName('BigDecimal'), 'java.math.BigDecimal');
+    });
+
+    test('validIdentifier', () => {
+        assert.equal(validIdentifier('java.math.BigDecimal'), true);
+    });
+
+    test('validPackage', () => {
+        assert.equal(validPackage('java.math.BigDecimal'), true);
+    });
+
+    test('packageSpecified', () => {
+        assert.equal(packageSpecified('java.math.BigDecimal'), true);
+    });
+
+    test('isKeywords', () => {
+        assert.equal(isKeywords('abstract'), true);
+    });
+
+    test('isJavaPrimitive', () => {
+        assert.equal(isJavaPrimitive('boolean'), true);
+    });
+});

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/frontend/test/unit/UserAuth.test.js
----------------------------------------------------------------------
diff --git a/modules/web-console/frontend/test/unit/UserAuth.test.js b/modules/web-console/frontend/test/unit/UserAuth.test.js
new file mode 100644
index 0000000..dbba1f6
--- /dev/null
+++ b/modules/web-console/frontend/test/unit/UserAuth.test.js
@@ -0,0 +1,35 @@
+/*
+ * 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 AuthService from '../../app/modules/user/Auth.service';
+
+suite('AuthServiceTestsSuite', () => {
+    test('SignIn', (done) => {
+        // TODO IGNITE-3262 Add test.
+        done();
+    });
+
+    test('SignUp', (done) => {
+        // TODO IGNITE-3262 Add test.
+        done();
+    });
+
+    test('Logout', (done) => {
+        // TODO IGNITE-3262 Add test.
+        done();
+    });
+});

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/frontend/views/403.jade
----------------------------------------------------------------------
diff --git a/modules/web-console/frontend/views/403.jade b/modules/web-console/frontend/views/403.jade
new file mode 100644
index 0000000..38d8bb5
--- /dev/null
+++ b/modules/web-console/frontend/views/403.jade
@@ -0,0 +1,22 @@
+//-
+    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 includes/header
+
+.error-page
+    .container
+        h1.error-page__title 403
+        h2.error-page__description You are not authorized

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/frontend/views/404.jade
----------------------------------------------------------------------
diff --git a/modules/web-console/frontend/views/404.jade b/modules/web-console/frontend/views/404.jade
new file mode 100644
index 0000000..7d2fc55
--- /dev/null
+++ b/modules/web-console/frontend/views/404.jade
@@ -0,0 +1,22 @@
+//-
+    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 includes/header
+
+.error-page
+    .container
+        h1.error-page__title 404
+        h2.error-page__description Page not found

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/frontend/views/base.jade
----------------------------------------------------------------------
diff --git a/modules/web-console/frontend/views/base.jade b/modules/web-console/frontend/views/base.jade
new file mode 100644
index 0000000..a910d1b
--- /dev/null
+++ b/modules/web-console/frontend/views/base.jade
@@ -0,0 +1,22 @@
+//-
+    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 includes/header
+
+.container.body-container
+    .main-content(ui-view='')
+
+include includes/footer

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/frontend/views/configuration/caches.jade
----------------------------------------------------------------------
diff --git a/modules/web-console/frontend/views/configuration/caches.jade b/modules/web-console/frontend/views/configuration/caches.jade
new file mode 100644
index 0000000..a1218ec
--- /dev/null
+++ b/modules/web-console/frontend/views/configuration/caches.jade
@@ -0,0 +1,53 @@
+//-
+    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.jade
+
+.docs-header
+    h1 Configure Ignite Caches
+.docs-body(ng-controller='cachesController')
+    ignite-information
+        ul
+            li Configure #[a(href='https://apacheignite.readme.io/docs/data-grid' target='_blank') memory] settings
+            li Configure persistence
+    div(ignite-loading='loadingCachesScreen' ignite-loading-text='Loading caches...' ignite-loading-position='top')
+        div(ng-show='ui.ready')
+            hr
+            +main-table('caches', 'caches', 'cacheName', 'selectItem(row)', '{{$index + 1}}) {{row.label}}', 'label')
+            .padding-top-dflt(bs-affix)
+                .panel-tip-container(data-placement='bottom' bs-tooltip='' data-title='Create new cache')
+                    button.btn.btn-primary(id='new-item' ng-click='createItem()') Add cache
+                +save-remove-clone-undo-buttons('cache')
+                hr
+            .bs-affix-fix
+            div(bs-collapse='' data-allow-multiple='true' ng-model='ui.activePanels')
+                form.form-horizontal(name='ui.inputForm' novalidate ng-if='contentVisible()')
+                    .panel-group
+                        include ../../app/modules/states/configuration/caches/general.jade
+                        include ../../app/modules/states/configuration/caches/memory.jade
+                        include ../../app/modules/states/configuration/caches/query.jade
+                        include ../../app/modules/states/configuration/caches/store.jade
+
+                        +advanced-options-toggle-default
+
+                        div(ng-show='ui.expanded')
+                            include ../../app/modules/states/configuration/caches/concurrency.jade
+                            include ../../app/modules/states/configuration/caches/node-filter.jade
+                            include ../../app/modules/states/configuration/caches/rebalance.jade
+                            include ../../app/modules/states/configuration/caches/server-near-cache.jade
+                            include ../../app/modules/states/configuration/caches/statistics.jade
+
+                            +advanced-options-toggle-default

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/frontend/views/configuration/clusters.jade
----------------------------------------------------------------------
diff --git a/modules/web-console/frontend/views/configuration/clusters.jade b/modules/web-console/frontend/views/configuration/clusters.jade
new file mode 100644
index 0000000..b10a477
--- /dev/null
+++ b/modules/web-console/frontend/views/configuration/clusters.jade
@@ -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.
+
+include ../../app/helpers/jade/mixins.jade
+
+.docs-header
+    h1 Configure Ignite Clusters
+.docs-body(ng-controller='clustersController')
+    ignite-information
+        ul
+            li Configure #[a(href='https://apacheignite.readme.io/docs/clustering' target='_blank') clusters] properties
+            li Associate clusters with caches and in-memory file systems
+    div(ignite-loading='loadingClustersScreen' ignite-loading-text='Loading clusters...' ignite-loading-position='top')
+        div(ng-show='ui.ready')
+            hr
+            +main-table('clusters', 'clusters', 'clusterName', 'selectItem(row)', '{{$index + 1}}) {{row.label}}', 'label')
+            .padding-top-dflt(bs-affix)
+                .panel-tip-container(data-placement='bottom' bs-tooltip='' data-title='Create new cluster')
+                    button.btn.btn-primary(id='new-item' ng-click='createItem()') Add cluster
+                +save-remove-clone-undo-buttons('cluster')
+                hr
+            .bs-affix-fix
+            div(bs-collapse='' data-allow-multiple='true' ng-model='ui.activePanels')
+                form.form-horizontal(name='ui.inputForm' novalidate ng-if='contentVisible()')
+                    .panel-group
+                        include ../../app/modules/states/configuration/clusters/general.jade
+
+                        +advanced-options-toggle-default
+
+                        div(ng-show='ui.expanded')
+                            
+                            include ../../app/modules/states/configuration/clusters/atomic.jade
+                            include ../../app/modules/states/configuration/clusters/binary.jade
+                            include ../../app/modules/states/configuration/clusters/cache-key-cfg.jade
+                            include ../../app/modules/states/configuration/clusters/collision.jade
+                            include ../../app/modules/states/configuration/clusters/communication.jade
+                            include ../../app/modules/states/configuration/clusters/connector.jade
+                            include ../../app/modules/states/configuration/clusters/deployment.jade
+                            include ../../app/modules/states/configuration/clusters/discovery.jade
+                            include ../../app/modules/states/configuration/clusters/events.jade
+                            include ../../app/modules/states/configuration/clusters/failover.jade
+                            include ../../app/modules/states/configuration/clusters/igfs.jade
+                            include ../../app/modules/states/configuration/clusters/logger.jade
+                            include ../../app/modules/states/configuration/clusters/marshaller.jade
+                            include ../../app/modules/states/configuration/clusters/metrics.jade
+                            include ../../app/modules/states/configuration/clusters/ssl.jade
+                            include ../../app/modules/states/configuration/clusters/swap.jade
+                            include ../../app/modules/states/configuration/clusters/thread.jade
+                            include ../../app/modules/states/configuration/clusters/time.jade
+                            include ../../app/modules/states/configuration/clusters/transactions.jade
+                            include ../../app/modules/states/configuration/clusters/attributes.jade
+
+                            +advanced-options-toggle-default

http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/frontend/views/configuration/domains-import.jade
----------------------------------------------------------------------
diff --git a/modules/web-console/frontend/views/configuration/domains-import.jade b/modules/web-console/frontend/views/configuration/domains-import.jade
new file mode 100644
index 0000000..d95e98a
--- /dev/null
+++ b/modules/web-console/frontend/views/configuration/domains-import.jade
@@ -0,0 +1,223 @@
+//-
+    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.jade
+
+mixin chk(mdl, change, tip)
+    input(type='checkbox' ng-model=mdl ng-change=change bs-tooltip='' data-title=tip data-trigger='hover' data-placement='top')
+
+mixin td-ellipses-lbl(w, lbl)
+    td.td-ellipsis(width='#{w}' style='min-width: #{w}; max-width: #{w}')
+        label #{lbl}
+
+.modal.modal-domain-import.center(role='dialog')
+    .modal-dialog.domains-import-dialog
+        .modal-content(ignite-loading='importDomainFromDb' ignite-loading-text='{{importDomain.loadingOptions.text}}')
+            #errors-container.modal-header.header
+                button.close(ng-click='$hide()' aria-hidden='true') &times;
+                h4.modal-title(ng-if='!importDomain.demo') Import domain models from database
+                h4.modal-title(ng-if='importDomain.demo') Import domain models from demo database
+            .modal-body
+                .import-domain-model-wizard-page(ng-if='importDomain.action == "drivers" && !importDomain.jdbcDriversNotFound')
+                .import-domain-model-wizard-page(ng-if='importDomain.action == "drivers" && importDomain.jdbcDriversNotFound')
+                    | Domain model could not be imported
+                    ul
+                        li Agent failed to find JDBC drivers
+                        li Copy required JDBC drivers into agent 'jdbc-drivers' folder and try again
+                        li Refer to agent README.txt for more information
+                .import-domain-model-wizard-page(ng-if='importDomain.action == "connect" && importDomain.demo')
+                    div(ng-if='demoConnection.db == "H2"')
+                        label Demo description:
+                        ul
+                            li In-memory H2 database server will be started inside agent
+                            li Database will be populated with sample tables
+                            li You could test domain model generation with this demo database
+                            li Click "Next" to continue
+                    div(ng-if='demoConnection.db != "H2"')
+                        label Demo could not be started
+                            ul
+                                li Agent failed to resolve H2 database jar
+                                li Copy h2-x.x.x.jar into agent 'jdbc-drivers' folder and try again
+                                li Refer to agent README.txt for more information
+                .import-domain-model-wizard-page(ng-if='importDomain.action == "connect" && !importDomain.demo')
+                    - var form = 'connectForm'
+
+                    form.form-horizontal(name=form novalidate)
+                        .settings-row
+                            label.col-xs-4.col-sm-2.col-md-2.required Driver JAR:
+                            .col-xs-8.col-sm-10.col-md-10
+                                i.tipField.fa.fa-question-circle(bs-tooltip='' data-title='Select appropriate JAR with JDBC driver<br> To add another driver you need to place it into "/jdbc-drivers" folder of Ignite Web Agent<br> Refer to Ignite Web Agent README.txt for for more information')
+                                .input-tip
+                                    button.select-toggle.form-control(id='jdbcDriverJar' bs-select data-container='.modal-domain-import' ng-model='ui.selectedJdbcDriverJar' ng-class='{placeholder: !(jdbcDriverJars && jdbcDriverJars.length > 0)}' placeholder='Choose JDBC driver' bs-options='item.value as item.label for item in jdbcDriverJars')
+                        .settings-row
+                            label.col-xs-4.col-sm-2.col-md-2.required JDBC driver:
+                            .col-xs-8.col-sm-10.col-md-10
+                                - var name = '"jdbcDriverClass"'
+                                i.tipField.fa.fa-question-circle(bs-tooltip='' data-title='Fully qualified class name of JDBC driver that will be used to connect to database')
+
+                                +form-field-feedback(name, 'javaBuiltInClass', 'JDBC Driver should not be the Java built-in class!')
+                                +form-field-feedback(name, 'javaKeywords', 'JDBC Driver could not contains reserved Java keyword!')
+                                +form-field-feedback(name, 'javaPackageSpecified', 'JDBC Driver does not have package specified!')
+                                +form-field-feedback(name, 'javaIdentifier', 'JDBC Driver is invalid Java identifier!')
+
+                                .input-tip
+                                    +ignite-form-field-input(name, 'selectedPreset.jdbcDriverClass', false, true, 'Enter fully qualified class name')(
+                                        data-java-identifier='true'
+                                        data-java-package-specified='true'
+                                        data-java-keywords='true'
+                                        data-java-built-in-class='true'
+                                    )
+                        .settings-row
+                            label.col-xs-4.col-sm-2.col-md-2.required JDBC URL:
+                            .col-xs-8.col-sm-10.col-md-10
+                                i.tipField.fa.fa-question-circle(bs-tooltip='' data-title='JDBC URL for connecting to database<br>Refer to your database documentation for details')
+                                .input-tip
+                                    +ignite-form-field-input('jdbcUrl', 'selectedPreset.jdbcUrl', false, true, 'JDBC URL')
+                        .settings-row
+                            label.col-xs-4.col-sm-2.col-md-2 User:
+                            .col-xs-8.col-sm-10.col-md-10
+                                i.tipField.fa.fa-question-circle(bs-tooltip='' data-title='User name for connecting to database')
+                                .input-tip
+                                    input.form-control(id='user' type='text' ng-model='selectedPreset.user')
+                        .settings-row
+                            label.col-xs-4.col-sm-2.col-md-2 Password:
+                            .col-xs-8.col-sm-10.col-md-10
+                                i.tipField.fa.fa-question-circle(bs-tooltip='' data-title='Password for connecting to database<br>Note, password would not be saved in preferences for security reasons')
+                                .input-tip
+                                    input.form-control(id='password' type='password' ng-model='selectedPreset.password' ignite-on-enter='importDomainNext()')
+                        .settings-row
+                            .checkbox
+                                label
+                                    input(id='tablesOnly' type='checkbox' ng-model='selectedPreset.tablesOnly')
+                                    | Tables only
+                                i.tipLabel.fa.fa-question-circle(bs-tooltip='' data-title='If selected, then only tables metadata will be parsed<br>Otherwise table and view metadata will be parsed')
+                .import-domain-model-wizard-page(ng-show='importDomain.action == "schemas"')
+                    table.table.metadata(st-table='importDomain.displayedSchemas' st-safe-src='importDomain.schemas')
+                        thead
+                            tr
+                                th.header(colspan='2')
+                                    .col-sm-4.pull-right(style='margin-bottom: 5px')
+                                        input.form-control(type='text' st-search='name' placeholder='Filter schemas...' ng-model='importDomain.displayedSchemasFilter' ng-change='selectSchema()')
+                            tr
+                                th(width='30px')
+                                    +chk('importDomain.allSchemasSelected',  'selectAllSchemas()', 'Select all schemas')
+                                th
+                                    label Schema
+                            tbody
+                                tr
+                                    td(colspan='2')
+                                        .scrollable-y(style='height: 213px')
+                                            table.table-modal-striped(id='importSchemasData')
+                                                tbody
+                                                    tr(ng-repeat='schema in importDomain.displayedSchemas')
+                                                        td(width='30px')
+                                                            input(type='checkbox' ng-model='schema.use' ng-change='selectSchema()')
+                                                        td
+                                                            label {{schema.name}}
+                .import-domain-model-wizard-page(ng-show='importDomain.action == "tables"')
+                    table.table.metadata(st-table='importDomain.displayedTables' st-safe-src='importDomain.tables')
+                        thead
+                            tr
+                                th.header(colspan='6')
+                                    .col-sm-4.pull-right(style='margin-bottom: 8px')
+                                        input.form-control(type='text' st-search='label' placeholder='Filter tables...' ng-model='importDomain.displayedTablesFilter' ng-change='selectTable()')
+                            tr
+                                th(width='30px')
+                                    +chk('importDomain.allTablesSelected',  'selectAllTables()', 'Select all tables')
+                                th(width='130px')
+                                    label Schema
+                                th(width='160px')
+                                    label Table name
+                                th(colspan=2 width='288px')
+                                    label Cache
+                                th
+                        tbody
+                            tr
+                                td(colspan='6')
+                                    .scrollable-y(style='height: 143px')
+                                        table.table-modal-striped(id='importTableData')
+                                            tbody
+                                                tr(ng-repeat='table in importDomain.displayedTables track by $index')
+                                                    td(width='30px' style='min-width: 30px; max-width: 30px')
+                                                        input(type='checkbox' ng-model='table.use' ng-change='selectTable()')
+                                                    +td-ellipses-lbl('130px', '{{table.schema}}')
+                                                    +td-ellipses-lbl('160px', '{{table.tbl}}')
+                                                    td(colspan='2' width='288px' style='min-width: 160px; max-width: 160px')
+                                                        div.td-ellipsis
+                                                            a(ng-if='!table.edit' ng-click='startEditDbTableCache(table)') {{tableActionView(table)}}
+                                                            div(style='display: flex' ng-if='table.edit')
+                                                                button.select-toggle.form-control(style='width: 35%; margin-right: 5px' bs-select ng-model='table.action' data-container='.modal-domain-import' bs-options='item.value as item.shortLabel for item in importActions')
+                                                                button.select-toggle.form-control(style='width: 65%; margin-right: 0' bs-select ng-model='table.cacheOrTemplate' data-container='.modal-domain-import' bs-options='item.value as item.label for item in table.cachesOrTemplates')
+                                                    td
+                    .settings-row
+                        label Defaults to be applied for filtered tables
+                        i.tipLabel.fa.fa-question-circle(bs-tooltip='' data-title='Select and apply options for caches generation')
+                    .settings-row
+                        .col-sm-11
+                            .col-sm-6(style='padding-right: 5px')
+                                button.select-toggle.form-control(bs-select ng-model='importCommon.action' data-container='.modal-domain-import' bs-options='item.value as item.label for item in importActions')
+                            .col-sm-6(style='padding-left: 5px; padding-right: 5px')
+                                button.select-toggle.form-control(bs-select ng-model='importCommon.cacheOrTemplate' data-container='.modal-domain-import' bs-options='item.value as item.label for item in importCommon.cachesOrTemplates')
+                        .col-sm-1(style='padding-left: 5px')
+                            button.btn.btn-primary(ng-click='applyDefaults()') Apply
+                .import-domain-model-wizard-page(ng-show='importDomain.action == "options"')
+                    - var form = 'optionsForm'
+                    form.form-horizontal(name='optionsForm' novalidate)
+                        .settings-row
+                            .col-xs-3.col-sm-2.col-md-2.required
+                                label.required Package:
+                            .col-xs-9.col-sm-10.col-md-10
+                                - var name = '"domainPackageName"'
+                                i.tipField.fa.fa-question-circle(bs-tooltip='' data-title='Package that will be used for POJOs generation')
+
+                                +form-field-feedback(name, 'javaPackageName', 'Package name is invalid')
+                                +form-field-feedback(name, 'javaKeywords', 'Package name could not contains reserved java keyword')
+
+                                .input-tip
+                                    +ignite-form-field-input(name, 'ui.packageName', false, true, 'Enter package name')(
+                                        data-java-keywords='true'
+                                        data-java-package-name='package-only'
+                                        ng-model-options='{allowInvalid: true}'
+                                    )
+                        .settings-row
+                            .checkbox
+                                label
+                                    input(id='domainBuiltinKeys' type='checkbox' ng-model='ui.builtinKeys')
+                                    | Use Java built-in types for keys
+                                    i.tipLabel.fa.fa-question-circle(bs-tooltip='' data-title='Use Java built-in types like "Integer", "Long", "String" instead of POJO generation in case when table primary key contains only one field')
+                        .settings-row
+                            .checkbox
+                                label
+                                    input(id='domainUsePrimitives' type='checkbox' ng-model='ui.usePrimitives')
+                                    | Use primitive types for NOT NULL table columns
+                                    i.tipLabel.fa.fa-question-circle(bs-tooltip='' data-title='Use primitive types like "int", "long", "double" for POJOs fields generation in case of NOT NULL columns')
+                        .settings-row
+                            .checkbox
+                                label
+                                    input(id='domainGenerateAliases' type='checkbox' ng-model='ui.generateAliases')
+                                    | Generate aliases for query fields
+                                    i.tipLabel.fa.fa-question-circle(bs-tooltip='' data-title='Generate aliases for query fields with database field names when database field name differ from Java field name')
+                        .settings-row
+                            .col-xs-3.col-sm-2.col-md-2.required
+                                label Clusters:
+                            .col-xs-9.col-sm-10.col-md-10
+                                i.tipField.fa.fa-question-circle(bs-tooltip='' data-title='Choose clusters that will be associated with generated caches')
+                                .input-tip
+                                    button.select-toggle.form-control(id='generatedCachesClusters' bs-select ng-model='ui.generatedCachesClusters' ng-class='{placeholder: !(ui.generatedCachesClusters && ui.generatedCachesClusters.length > 0)}' data-container='.modal-domain-import' data-multiple='1' placeholder='Choose clusters for generated caches' bs-options='item.value as item.label for item in clusters')
+            .modal-footer
+                label(ng-hide='importDomain.action == "drivers" || (importDomain.action == "connect" && importDomain.demo)').labelField {{importDomain.info}}
+                a.btn.btn-primary(ng-hide='importDomain.action == "drivers" || importDomain.action == "connect"' ng-click='importDomainPrev()' bs-tooltip='' data-title='{{prevTooltipText()}}' data-placement='bottom') Prev
+                a.btn.btn-primary(ng-click='importDomainNext()' ng-disabled='!importDomainNextAvailable()' bs-tooltip='' data-title='{{nextTooltipText()}}' data-placement='bottom') {{importDomain.button}}