ignite-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From akuznet...@apache.org
Subject [17/21] ignite git commit: IGNITE-843 Implemented Web Console.
Date Tue, 17 May 2016 16:22:59 GMT
http://git-wip-us.apache.org/repos/asf/ignite/blob/eb5ac0ae/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
new file mode 100644
index 0000000..2bbf11f
--- /dev/null
+++ b/modules/web-console/src/main/js/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/eb5ac0ae/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
new file mode 100644
index 0000000..8bd5ba3
--- /dev/null
+++ b/modules/web-console/src/main/js/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/eb5ac0ae/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
new file mode 100644
index 0000000..99830b0
--- /dev/null
+++ b/modules/web-console/src/main/js/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/eb5ac0ae/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
new file mode 100644
index 0000000..f9776a2
--- /dev/null
+++ b/modules/web-console/src/main/js/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/eb5ac0ae/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
new file mode 100644
index 0000000..67e19b9
--- /dev/null
+++ b/modules/web-console/src/main/js/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;
+}];

http://git-wip-us.apache.org/repos/asf/ignite/blob/eb5ac0ae/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
new file mode 100644
index 0000000..cf266e1
--- /dev/null
+++ b/modules/web-console/src/main/js/app/modules/configuration/generator/Pom.service.js
@@ -0,0 +1,214 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 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) {
+        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 dialect = {};
+        const deps = [];
+        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'))
+                    dialect[storeFactory.dialect] = true;
+            }
+        });
+
+        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);
+
+        if (cluster.discovery.kind === 'Cloud')
+            this.addDependency(deps, 'org.apache.ignite', 'ignite-cloud', igniteVersion);
+        else if (cluster.discovery.kind === 'S3')
+            this.addDependency(deps, 'org.apache.ignite', 'ignite-aws', igniteVersion);
+        else if (cluster.discovery.kind === 'GoogleStorage')
+            this.addDependency(deps, 'org.apache.ignite', 'ignite-gce', igniteVersion);
+        else if (cluster.discovery.kind === 'ZooKeeper')
+            this.addDependency(deps, 'org.apache.ignite', 'ignite-zookeeper', 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);
+
+        dialect.Generic && this.addDependency(deps, 'com.mchange', 'c3p0', '0.9.5.1');
+
+        dialect.MySQL && this.addDependency(deps, 'mysql', 'mysql-connector-java', '5.1.37');
+
+        dialect.PostgreSQL && this.addDependency(deps, 'org.postgresql', 'postgresql', '9.4-1204-jdbc42');
+
+        dialect.H2 && this.addDependency(deps, 'com.h2database', 'h2', '1.3.175');
+
+        dialect.Oracle && this.addDependency(deps, 'oracle', 'jdbc', '11.2', 'ojdbc6.jar');
+
+        dialect.DB2 && this.addDependency(deps, 'ibm', 'jdbc', '4.19.26', 'db2jcc4.jar');
+
+        dialect.SQLServer && this.addDependency(deps, 'microsoft', 'jdbc', '4.1', 'sqljdbc41.jar');
+
+        this.dependencies(res, cluster, deps);
+
+        res.needEmptyLine = true;
+
+        this.build(res, cluster, excludeGroupIds);
+
+        return res;
+    }
+}
+
+export default ['GeneratorPom', GeneratorPom];

http://git-wip-us.apache.org/repos/asf/ignite/blob/eb5ac0ae/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
new file mode 100644
index 0000000..58d1ce0
--- /dev/null
+++ b/modules/web-console/src/main/js/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/eb5ac0ae/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
new file mode 100644
index 0000000..e51553b
--- /dev/null
+++ b/modules/web-console/src/main/js/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/eb5ac0ae/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
new file mode 100644
index 0000000..98e9903
--- /dev/null
+++ b/modules/web-console/src/main/js/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/eb5ac0ae/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
new file mode 100644
index 0000000..ed4adb8
--- /dev/null
+++ b/modules/web-console/src/main/js/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/eb5ac0ae/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
new file mode 100644
index 0000000..05518d3
--- /dev/null
+++ b/modules/web-console/src/main/js/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/eb5ac0ae/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
new file mode 100644
index 0000000..7aab10f
--- /dev/null
+++ b/modules/web-console/src/main/js/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/eb5ac0ae/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
new file mode 100644
index 0000000..18a2174
--- /dev/null
+++ b/modules/web-console/src/main/js/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 template from './dialog.jade!';
+
+export default ['IgniteDialog', ['$modal', ($modal) => {
+    const defaults = {
+        template: template(),
+        placement: 'center',
+        show: false
+    };
+
+    return function(options) {
+        options = _.extend({}, defaults, options);
+
+        return $modal(options);
+    };
+}]];

http://git-wip-us.apache.org/repos/asf/ignite/blob/eb5ac0ae/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
new file mode 100644
index 0000000..0043709
--- /dev/null
+++ b/modules/web-console/src/main/js/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/eb5ac0ae/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
new file mode 100644
index 0000000..c9ba9f9
--- /dev/null
+++ b/modules/web-console/src/main/js/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/eb5ac0ae/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
new file mode 100644
index 0000000..035fed4
--- /dev/null
+++ b/modules/web-console/src/main/js/app/modules/form/field/bs-select-placeholder.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.
+ */
+
+// 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 (value && (!attrs.multiple || value.length))
+                $element.removeClass('placeholder');
+            else {
+                $element.html(attrs.placeholder);
+                $element.addClass('placeholder');
+            }
+        };
+    };
+
+    return {
+        priority: 1,
+        restrict: 'A',
+        link,
+        require: ['?ngModel']
+    };
+}]];

http://git-wip-us.apache.org/repos/asf/ignite/blob/eb5ac0ae/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
new file mode 100644
index 0000000..91be945
--- /dev/null
+++ b/modules/web-console/src/main/js/app/modules/form/field/down.directive.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.
+ */
+
+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/eb5ac0ae/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
new file mode 100644
index 0000000..fe4d948
--- /dev/null
+++ b/modules/web-console/src/main/js/app/modules/form/field/dropdown.directive.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.
+ */
+
+import template from './dropdown.jade!';
+
+export default ['igniteFormFieldDropdown', ['IgniteFormGUID', '$table', (guid, $table) => {
+    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);
+
+        // TODO LEGACY
+        scope.tableReset = () => {
+            $table.tableSaveAndReset();
+        };
+    };
+
+    return {
+        restrict: 'E',
+        scope: {
+            id: '@',
+            name: '@',
+            required: '=ngRequired',
+            value: '=ngModel',
+
+            focus: '=ngFocus',
+
+            onEnter: '@'
+        },
+        bindToController: {
+            value: '=ngModel',
+            placeholder: '@',
+            options: '=',
+            ngDisabled: '=',
+            multiple: '='
+        },
+        link,
+        template,
+        controller,
+        controllerAs: 'dropdown',
+        replace: true,
+        transclude: true,
+        require: ['^form', '?^igniteFormField']
+    };
+}]];

http://git-wip-us.apache.org/repos/asf/ignite/blob/eb5ac0ae/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
new file mode 100644
index 0000000..48b55d9
--- /dev/null
+++ b/modules/web-console/src/main/js/app/modules/form/field/dropdown.jade
@@ -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.
+
+.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'
+
+        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'
+
+        on-enter='{{ onEnter }}'
+
+        tabindex='0'
+
+        data-ng-focus='tableReset()'
+    )
+
+    span(ng-transclude='')

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

http://git-wip-us.apache.org/repos/asf/ignite/blob/eb5ac0ae/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
new file mode 100644
index 0000000..0e3fe8d
--- /dev/null
+++ b/modules/web-console/src/main/js/app/modules/form/field/field.directive.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.
+ */
+
+import template 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: '@'
+        },
+        template,
+        controller,
+        controllerAs: 'field',
+        replace: true,
+        transclude: true,
+        require: '^form'
+    };
+}]];

http://git-wip-us.apache.org/repos/asf/ignite/blob/eb5ac0ae/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
new file mode 100644
index 0000000..08250ac
--- /dev/null
+++ b/modules/web-console/src/main/js/app/modules/form/field/field.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.
+
+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')

http://git-wip-us.apache.org/repos/asf/ignite/blob/eb5ac0ae/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
new file mode 100644
index 0000000..058bcc3
--- /dev/null
+++ b/modules/web-console/src/main/js/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 ['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/eb5ac0ae/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
new file mode 100644
index 0000000..c963cc1
--- /dev/null
+++ b/modules/web-console/src/main/js/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', [() => {
+    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/eb5ac0ae/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
new file mode 100644
index 0000000..5d77eab
--- /dev/null
+++ b/modules/web-console/src/main/js/app/modules/form/field/input/checkbox.directive.js
@@ -0,0 +1,67 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import template from './checkbox.jade!';
+
+export default ['igniteFormFieldInputCheckbox', ['IgniteFormGUID', '$table', (guid, $table) => {
+    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);
+
+        // TODO LEGACY
+        scope.tableReset = () => {
+            $table.tableSaveAndReset();
+        };
+    };
+
+    return {
+        restrict: 'E',
+        scope: {
+            id: '@',
+            name: '@',
+            required: '=ngRequired',
+            disabled: '=ngDisabled',
+
+            focus: '=ngFocus',
+
+            value: '=ngModel'
+        },
+        link,
+        template,
+        replace: true,
+        transclude: true,
+        require: ['^form', '?^igniteFormField']
+    };
+}]];

http://git-wip-us.apache.org/repos/asf/ignite/blob/eb5ac0ae/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
new file mode 100644
index 0000000..477d4b2
--- /dev/null
+++ b/modules/web-console/src/main/js/app/modules/form/field/input/checkbox.jade
@@ -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.
+
+.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/eb5ac0ae/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
new file mode 100644
index 0000000..0cd9d69
--- /dev/null
+++ b/modules/web-console/src/main/js/app/modules/form/field/input/datalist.directive.js
@@ -0,0 +1,123 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import template from './datalist.jade!';
+
+export default ['igniteFormFieldInputDatalist', ['IgniteFormGUID', '$table', (guid, $table) => {
+    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 (JSON.stringify(scope.value) !== JSON.stringify(form.$defaults[name]))
+                ngModel.$setDirty();
+            else
+                ngModel.$setPristine();
+
+            setTimeout(checkValid, 100); // Use setTimeout() workaround of problem of two controllers.
+        };
+
+        ngModel.$render = () => {
+            scope.value = ngModel.$modelValue;
+        };
+
+        // TODO LEGACY
+        scope.tableReset = () => {
+            $table.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,
+        template,
+        replace: true,
+        transclude: true,
+        require: ['ngModel', '^form', '?^igniteFormField']
+    };
+}]];

http://git-wip-us.apache.org/repos/asf/ignite/blob/eb5ac0ae/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
new file mode 100644
index 0000000..723b348
--- /dev/null
+++ b/modules/web-console/src/main/js/app/modules/form/field/input/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 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'
+        retain-selection
+    )
+
+    +feedback(true, 'required', '{{ label.name }} could not be empty!')
+
+    span.transclude-here

http://git-wip-us.apache.org/repos/asf/ignite/blob/eb5ac0ae/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
new file mode 100644
index 0000000..0c7a101
--- /dev/null
+++ b/modules/web-console/src/main/js/app/modules/form/field/input/number.directive.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 template from './number.jade!';
+
+export default ['igniteFormFieldInputNumber', ['IgniteFormGUID', '$table', (guid, $table) => {
+    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);
+
+        // TODO LEGACY
+        scope.tableReset = () => {
+            $table.tableSaveAndReset();
+        };
+    };
+
+    return {
+        restrict: 'E',
+        scope: {
+            id: '@',
+            name: '@',
+            placeholder: '@',
+            required: '=ngRequired',
+            disabled: '=ngDisabled',
+
+            focus: '=ngFocus',
+
+            min: '@',
+            max: '@',
+            step: '@',
+            value: '=ngModel'
+        },
+        link,
+        template,
+        replace: true,
+        transclude: true,
+        require: ['^form', '?^igniteFormField']
+    };
+}]];

http://git-wip-us.apache.org/repos/asf/ignite/blob/eb5ac0ae/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
new file mode 100644
index 0000000..e72a1d0
--- /dev/null
+++ b/modules/web-console/src/main/js/app/modules/form/field/input/number.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 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/eb5ac0ae/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
new file mode 100644
index 0000000..c76bebd
--- /dev/null
+++ b/modules/web-console/src/main/js/app/modules/form/field/input/text.css
@@ -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/eb5ac0ae/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
new file mode 100644
index 0000000..ba4407f
--- /dev/null
+++ b/modules/web-console/src/main/js/app/modules/form/field/input/text.directive.js
@@ -0,0 +1,124 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import template from './text.jade!';
+import './text.css!';
+
+export default ['igniteFormFieldInputText', ['IgniteFormGUID', '$table', (guid, $table) => {
+    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 (JSON.stringify(scope.value) !== JSON.stringify(form.$defaults[name]))
+                ngModel.$setDirty();
+            else
+                ngModel.$setPristine();
+
+            setTimeout(checkValid, 100); // Use setTimeout() workaround of problem of two controllers.
+        };
+
+        ngModel.$render = () => {
+            scope.value = ngModel.$modelValue;
+        };
+
+        // TODO LEGACY
+        scope.tableReset = () => {
+            $table.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,
+        template,
+        replace: true,
+        transclude: true,
+        require: ['ngModel', '^form', '?^igniteFormField']
+    };
+}]];

http://git-wip-us.apache.org/repos/asf/ignite/blob/eb5ac0ae/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
new file mode 100644
index 0000000..40aef79
--- /dev/null
+++ b/modules/web-console/src/main/js/app/modules/form/field/input/text.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.
+
+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', '{{ label.name }} could not be empty!')
+
+    span.transclude-here

http://git-wip-us.apache.org/repos/asf/ignite/blob/eb5ac0ae/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
new file mode 100644
index 0000000..9b812d7
--- /dev/null
+++ b/modules/web-console/src/main/js/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('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/eb5ac0ae/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
new file mode 100644
index 0000000..5005280
--- /dev/null
+++ b/modules/web-console/src/main/js/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/eb5ac0ae/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
new file mode 100644
index 0000000..d31bdc5
--- /dev/null
+++ b/modules/web-console/src/main/js/app/modules/form/field/up.directive.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.
+ */
+
+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/eb5ac0ae/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
new file mode 100644
index 0000000..57a92fa
--- /dev/null
+++ b/modules/web-console/src/main/js/app/modules/form/form.module.js
@@ -0,0 +1,101 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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++}`;
+}]);


Mime
View raw message