Merge "YangUI - API - Fixed list filtering alerts"
authorMaxime Millette-Coulombe <mmcoulombe@inocybe.com>
Wed, 7 Sep 2016 12:43:09 +0000 (12:43 +0000)
committerGerrit Code Review <gerrit@opendaylight.org>
Wed, 7 Sep 2016 12:43:09 +0000 (12:43 +0000)
201 files changed:
.gitignore
archetype/pom.xml
archetype/src/main/resources/archetype-resources/pom.xml
bundles/authentication/pom.xml
bundles/core/pom.xml
bundles/general/pom.xml
bundles/layout/pom.xml
bundles/login/pom.xml
bundles/navigation/pom.xml
bundles/node/pom.xml
bundles/pom.xml
bundles/sigmatopology/pom.xml
bundles/topbar/pom.xml
bundles/topology/pom.xml
bundles/yangman/pom.xml [new file with mode: 0644]
bundles/yangman/src/main/resources/OSGI-INF/blueprint/blueprint.xml [new file with mode: 0644]
bundles/yangui/pom.xml
bundles/yangutils/pom.xml
bundles/yangvisualizer/pom.xml
dlux-web/bower.json
dlux-web/build.config.js
dlux-web/pom.xml
dlux-web/src/less/design.less
dlux-web/src/less/main.less
features/pom.xml
features/src/main/features/features.xml
loader/api/pom.xml
loader/impl/pom.xml
modules/common-authentication-resources/pom.xml
modules/common-general-resources/pom.xml
modules/common-layout-resources/pom.xml
modules/common-layout-resources/src/main/resources/layout/index.tpl.html
modules/common-login-resources/pom.xml
modules/common-navigation-resources/pom.xml
modules/common-navigation-resources/src/main/resources/navigation/navigation.less
modules/common-sigmatopology-resources/pom.xml
modules/common-topbar-resources/pom.xml
modules/common-yangutils-resources/pom.xml
modules/common-yangutils-resources/src/main/resources/yangutils/constants.js
modules/common-yangutils-resources/src/main/resources/yangutils/services/api-builder.services.js
modules/common-yangutils-resources/src/main/resources/yangutils/services/custom-funct.services.js
modules/common-yangutils-resources/src/main/resources/yangutils/services/data-backup.services.js
modules/common-yangutils-resources/src/main/resources/yangutils/services/filter-node-wrapper.services.js
modules/common-yangutils-resources/src/main/resources/yangutils/services/list-filtering.services.js
modules/common-yangutils-resources/src/main/resources/yangutils/services/module-connector.services.js
modules/common-yangutils-resources/src/main/resources/yangutils/services/node-utils.services.js
modules/common-yangutils-resources/src/main/resources/yangutils/services/node-wrapper.services.js
modules/common-yangutils-resources/src/main/resources/yangutils/services/path-utils.services.js
modules/common-yangutils-resources/src/main/resources/yangutils/services/sync.services.js
modules/common-yangutils-resources/src/main/resources/yangutils/services/type-wrapper.services.js
modules/common-yangutils-resources/src/main/resources/yangutils/services/yang-utils.services.js
modules/common-yangutils-resources/src/main/resources/yangutils/services/yin-parser.services.js
modules/connection_manager-resources/pom.xml
modules/container-resources/pom.xml
modules/core-resources/pom.xml
modules/flow-resources/pom.xml
modules/loader-resources/pom.xml
modules/loader-resources/src/main/resources/app/app.module.js
modules/loader-resources/src/main/resources/assets/css/sb-admin.css
modules/loader-resources/src/main/resources/assets/images/logo_yangman.png [new file with mode: 0644]
modules/loader-resources/src/main/resources/assets/js/codemirror/addon/edit/matchbrackets.js [moved from modules/yangui-resources/src/main/resources/yangui/assets/js/codemirror/addon/edit/matchbrackets.js with 100% similarity]
modules/loader-resources/src/main/resources/assets/js/codemirror/addon/hint/json-parameters-hint.js [moved from modules/yangui-resources/src/main/resources/yangui/assets/js/codemirror/addon/hint/yangui-json-hint.js with 84% similarity]
modules/loader-resources/src/main/resources/assets/js/codemirror/addon/hint/show-hint.js [moved from modules/yangui-resources/src/main/resources/yangui/assets/js/codemirror/addon/hint/show-hint.js with 100% similarity]
modules/loader-resources/src/main/resources/assets/js/codemirror/addon/hint/show-hint.less [moved from modules/yangui-resources/src/main/resources/yangui/assets/js/codemirror/addon/hint/show-hint.less with 100% similarity]
modules/loader-resources/src/main/resources/assets/js/codemirror/addon/mode/loadmode.js [moved from modules/yangui-resources/src/main/resources/yangui/assets/js/codemirror/addon/mode/loadmode.js with 100% similarity]
modules/loader-resources/src/main/resources/assets/js/codemirror/lib/codemirror.js [moved from modules/yangui-resources/src/main/resources/yangui/assets/js/codemirror/lib/codemirror.js with 99% similarity]
modules/loader-resources/src/main/resources/assets/js/codemirror/lib/codemirror.less [moved from modules/yangui-resources/src/main/resources/yangui/assets/js/codemirror/lib/codemirror.less with 100% similarity]
modules/loader-resources/src/main/resources/assets/js/codemirror/mode/javascript/javascript.js [moved from modules/yangui-resources/src/main/resources/yangui/assets/js/codemirror/mode/javascript/javascript.js with 100% similarity]
modules/loader-resources/src/main/resources/assets/js/codemirror/theme/eclipse-disabled.less [moved from modules/yangui-resources/src/main/resources/yangui/assets/js/codemirror/theme/eclipse-disabled.less with 100% similarity]
modules/loader-resources/src/main/resources/assets/js/codemirror/theme/eclipse.less [moved from modules/yangui-resources/src/main/resources/yangui/assets/js/codemirror/theme/eclipse.less with 100% similarity]
modules/loader-resources/src/main/resources/index.html
modules/loader-resources/src/main/resources/main.js
modules/network-resources/pom.xml
modules/node-resources/pom.xml
modules/node-resources/src/main/resources/node/node.less
modules/node-resources/src/main/resources/node/root.tpl.html
modules/pom.xml
modules/topology-resources/pom.xml
modules/yangman-resources/pom.xml [new file with mode: 0644]
modules/yangman-resources/src/main/resources/yangman/assets/data/locale-en_US.json [new file with mode: 0644]
modules/yangman-resources/src/main/resources/yangman/assets/images/icon-augment.svg [new file with mode: 0644]
modules/yangman-resources/src/main/resources/yangman/controllers/edit-collection-dialog.controller.js [new file with mode: 0644]
modules/yangman-resources/src/main/resources/yangman/controllers/form/ym-augmentation-modal.controller.js [new file with mode: 0644]
modules/yangman-resources/src/main/resources/yangman/controllers/form/ym-case.controller.js [new file with mode: 0644]
modules/yangman-resources/src/main/resources/yangman/controllers/form/ym-choice.controller.js [new file with mode: 0644]
modules/yangman-resources/src/main/resources/yangman/controllers/form/ym-container.controller.js [new file with mode: 0644]
modules/yangman-resources/src/main/resources/yangman/controllers/form/ym-input.controller.js [new file with mode: 0644]
modules/yangman-resources/src/main/resources/yangman/controllers/form/ym-leaf-list.controller.js [new file with mode: 0644]
modules/yangman-resources/src/main/resources/yangman/controllers/form/ym-leaf.controller.js [new file with mode: 0644]
modules/yangman-resources/src/main/resources/yangman/controllers/form/ym-list.controller.js [new file with mode: 0644]
modules/yangman-resources/src/main/resources/yangman/controllers/form/ym-output.controller.js [new file with mode: 0644]
modules/yangman-resources/src/main/resources/yangman/controllers/form/ym-rpc.controller.js [new file with mode: 0644]
modules/yangman-resources/src/main/resources/yangman/controllers/form/ym-type-bit.controller.js [new file with mode: 0644]
modules/yangman-resources/src/main/resources/yangman/controllers/form/ym-type-boolean.controller.js [new file with mode: 0644]
modules/yangman-resources/src/main/resources/yangman/controllers/form/ym-type-empty.controller.js [new file with mode: 0644]
modules/yangman-resources/src/main/resources/yangman/controllers/form/ym-type-enum.controller.js [new file with mode: 0644]
modules/yangman-resources/src/main/resources/yangman/controllers/form/ym-type.controller.js [new file with mode: 0644]
modules/yangman-resources/src/main/resources/yangman/controllers/module-detail.controller.js [new file with mode: 0644]
modules/yangman-resources/src/main/resources/yangman/controllers/modules-list.controller.js [new file with mode: 0644]
modules/yangman-resources/src/main/resources/yangman/controllers/params-admin.controller.js [new file with mode: 0644]
modules/yangman-resources/src/main/resources/yangman/controllers/request-data.controller.js [new file with mode: 0644]
modules/yangman-resources/src/main/resources/yangman/controllers/request-header.controller.js [new file with mode: 0644]
modules/yangman-resources/src/main/resources/yangman/controllers/requests-list.controller.js [new file with mode: 0644]
modules/yangman-resources/src/main/resources/yangman/controllers/save-req-dialog.controller.js [new file with mode: 0644]
modules/yangman-resources/src/main/resources/yangman/controllers/yang-form.controller.js [new file with mode: 0644]
modules/yangman-resources/src/main/resources/yangman/controllers/yangman.controller.js [new file with mode: 0644]
modules/yangman-resources/src/main/resources/yangman/directives/abn-tree.directive.js [new file with mode: 0644]
modules/yangman-resources/src/main/resources/yangman/directives/read_file.directive.js [new file with mode: 0644]
modules/yangman-resources/src/main/resources/yangman/directives/ui-codemirror.directive.js [new file with mode: 0644]
modules/yangman-resources/src/main/resources/yangman/directives/yang-form-menu.directive.js [new file with mode: 0644]
modules/yangman-resources/src/main/resources/yangman/directives/ym-info-box.directive.js [new file with mode: 0644]
modules/yangman-resources/src/main/resources/yangman/main.js [new file with mode: 0644]
modules/yangman-resources/src/main/resources/yangman/models/baselist.model.js [new file with mode: 0644]
modules/yangman-resources/src/main/resources/yangman/models/collection.model.js [new file with mode: 0644]
modules/yangman-resources/src/main/resources/yangman/models/collectionlist.model.js [new file with mode: 0644]
modules/yangman-resources/src/main/resources/yangman/models/history-request.model.js [new file with mode: 0644]
modules/yangman-resources/src/main/resources/yangman/models/historylist.model.js [new file with mode: 0644]
modules/yangman-resources/src/main/resources/yangman/models/parameter.model.js [new file with mode: 0644]
modules/yangman-resources/src/main/resources/yangman/models/parameterslist.model.js [new file with mode: 0644]
modules/yangman-resources/src/main/resources/yangman/services/handle-file.services.js [new file with mode: 0644]
modules/yangman-resources/src/main/resources/yangman/services/mount-points-connector.services.js [new file with mode: 0644]
modules/yangman-resources/src/main/resources/yangman/services/parameters.services.js [new file with mode: 0644]
modules/yangman-resources/src/main/resources/yangman/services/plugins-handler.services.js [new file with mode: 0644]
modules/yangman-resources/src/main/resources/yangman/services/plugins-unsetter.services.js [new file with mode: 0644]
modules/yangman-resources/src/main/resources/yangman/services/plugins/ymDisplayMountPoints.services.js [new file with mode: 0644]
modules/yangman-resources/src/main/resources/yangman/services/requests.services.js [new file with mode: 0644]
modules/yangman-resources/src/main/resources/yangman/services/time-tracking.services.js [new file with mode: 0644]
modules/yangman-resources/src/main/resources/yangman/services/yangman-design.services.js [new file with mode: 0644]
modules/yangman-resources/src/main/resources/yangman/services/yangman.services.js [new file with mode: 0644]
modules/yangman-resources/src/main/resources/yangman/views/directives/abn-tree.tpl.html [new file with mode: 0644]
modules/yangman-resources/src/main/resources/yangman/views/directives/yang-form-menu.tpl.html [new file with mode: 0644]
modules/yangman-resources/src/main/resources/yangman/views/directives/ym-info-box.tpl.html [new file with mode: 0644]
modules/yangman-resources/src/main/resources/yangman/views/index.tpl.html [new file with mode: 0644]
modules/yangman-resources/src/main/resources/yangman/views/leftpanel/collections-tab.tpl.html [new file with mode: 0644]
modules/yangman-resources/src/main/resources/yangman/views/leftpanel/edit-collection-dialog.tpl.html [new file with mode: 0644]
modules/yangman-resources/src/main/resources/yangman/views/leftpanel/history-tab.tpl.html [new file with mode: 0644]
modules/yangman-resources/src/main/resources/yangman/views/leftpanel/module-detail.tpl.html [new file with mode: 0644]
modules/yangman-resources/src/main/resources/yangman/views/leftpanel/modules-tab.tpl.html [new file with mode: 0644]
modules/yangman-resources/src/main/resources/yangman/views/leftpanel/request-item.tpl.html [new file with mode: 0644]
modules/yangman-resources/src/main/resources/yangman/views/leftpanel/save-req-dialog.tpl.html [new file with mode: 0644]
modules/yangman-resources/src/main/resources/yangman/views/popup/parameters-admin.tpl.html [new file with mode: 0644]
modules/yangman-resources/src/main/resources/yangman/views/rightpanel/detail.tpl.html [new file with mode: 0644]
modules/yangman-resources/src/main/resources/yangman/views/rightpanel/form/augmentations.tpl.html [new file with mode: 0644]
modules/yangman-resources/src/main/resources/yangman/views/rightpanel/form/config/case.tpl.html [new file with mode: 0644]
modules/yangman-resources/src/main/resources/yangman/views/rightpanel/form/config/choice.tpl.html [new file with mode: 0644]
modules/yangman-resources/src/main/resources/yangman/views/rightpanel/form/config/container.tpl.html [new file with mode: 0644]
modules/yangman-resources/src/main/resources/yangman/views/rightpanel/form/config/input.tpl.html [new file with mode: 0644]
modules/yangman-resources/src/main/resources/yangman/views/rightpanel/form/config/leaf-list.tpl.html [new file with mode: 0644]
modules/yangman-resources/src/main/resources/yangman/views/rightpanel/form/config/leaf.tpl.html [new file with mode: 0644]
modules/yangman-resources/src/main/resources/yangman/views/rightpanel/form/config/list-filtered-data-top.tpl.html [new file with mode: 0644]
modules/yangman-resources/src/main/resources/yangman/views/rightpanel/form/config/list.tpl.html [new file with mode: 0644]
modules/yangman-resources/src/main/resources/yangman/views/rightpanel/form/config/output.tpl.html [new file with mode: 0644]
modules/yangman-resources/src/main/resources/yangman/views/rightpanel/form/config/rpc.tpl.html [new file with mode: 0644]
modules/yangman-resources/src/main/resources/yangman/views/rightpanel/form/config/types/binary.tpl.html [new file with mode: 0644]
modules/yangman-resources/src/main/resources/yangman/views/rightpanel/form/config/types/bits.tpl.html [new file with mode: 0644]
modules/yangman-resources/src/main/resources/yangman/views/rightpanel/form/config/types/boolean.tpl.html [new file with mode: 0644]
modules/yangman-resources/src/main/resources/yangman/views/rightpanel/form/config/types/decimal64.tpl.html [new file with mode: 0644]
modules/yangman-resources/src/main/resources/yangman/views/rightpanel/form/config/types/default.tpl.html [new file with mode: 0644]
modules/yangman-resources/src/main/resources/yangman/views/rightpanel/form/config/types/empty.tpl.html [new file with mode: 0644]
modules/yangman-resources/src/main/resources/yangman/views/rightpanel/form/config/types/enumeration.tpl.html [new file with mode: 0644]
modules/yangman-resources/src/main/resources/yangman/views/rightpanel/form/config/types/identityref.tpl.html [new file with mode: 0644]
modules/yangman-resources/src/main/resources/yangman/views/rightpanel/form/config/types/instance-identifier.tpl.html [new file with mode: 0644]
modules/yangman-resources/src/main/resources/yangman/views/rightpanel/form/config/types/int16.tpl.html [new file with mode: 0644]
modules/yangman-resources/src/main/resources/yangman/views/rightpanel/form/config/types/int32.tpl.html [new file with mode: 0644]
modules/yangman-resources/src/main/resources/yangman/views/rightpanel/form/config/types/int64.tpl.html [new file with mode: 0644]
modules/yangman-resources/src/main/resources/yangman/views/rightpanel/form/config/types/int8.tpl.html [new file with mode: 0644]
modules/yangman-resources/src/main/resources/yangman/views/rightpanel/form/config/types/leafref.tpl.html [new file with mode: 0644]
modules/yangman-resources/src/main/resources/yangman/views/rightpanel/form/config/types/string.tpl.html [new file with mode: 0644]
modules/yangman-resources/src/main/resources/yangman/views/rightpanel/form/config/types/uint16.tpl.html [new file with mode: 0644]
modules/yangman-resources/src/main/resources/yangman/views/rightpanel/form/config/types/uint32.tpl.html [new file with mode: 0644]
modules/yangman-resources/src/main/resources/yangman/views/rightpanel/form/config/types/uint64.tpl.html [new file with mode: 0644]
modules/yangman-resources/src/main/resources/yangman/views/rightpanel/form/config/types/uint8.tpl.html [new file with mode: 0644]
modules/yangman-resources/src/main/resources/yangman/views/rightpanel/form/config/types/union.tpl.html [new file with mode: 0644]
modules/yangman-resources/src/main/resources/yangman/views/rightpanel/form/list-data-top.tpl.html [new file with mode: 0644]
modules/yangman-resources/src/main/resources/yangman/views/rightpanel/form/operational/case.tpl.html [new file with mode: 0644]
modules/yangman-resources/src/main/resources/yangman/views/rightpanel/form/operational/choice.tpl.html [new file with mode: 0644]
modules/yangman-resources/src/main/resources/yangman/views/rightpanel/form/operational/container.tpl.html [new file with mode: 0644]
modules/yangman-resources/src/main/resources/yangman/views/rightpanel/form/operational/input.tpl.html [new file with mode: 0644]
modules/yangman-resources/src/main/resources/yangman/views/rightpanel/form/operational/leaf-list.tpl.html [new file with mode: 0644]
modules/yangman-resources/src/main/resources/yangman/views/rightpanel/form/operational/leaf.tpl.html [new file with mode: 0644]
modules/yangman-resources/src/main/resources/yangman/views/rightpanel/form/operational/list-filtered-data-top.tpl.html [new file with mode: 0644]
modules/yangman-resources/src/main/resources/yangman/views/rightpanel/form/operational/list.tpl.html [new file with mode: 0644]
modules/yangman-resources/src/main/resources/yangman/views/rightpanel/form/operational/output.tpl.html [new file with mode: 0644]
modules/yangman-resources/src/main/resources/yangman/views/rightpanel/form/operational/rpc.tpl.html [new file with mode: 0644]
modules/yangman-resources/src/main/resources/yangman/views/rightpanel/form/operations/rpc.tpl.html [new file with mode: 0644]
modules/yangman-resources/src/main/resources/yangman/views/rightpanel/request-data.tpl.html [new file with mode: 0644]
modules/yangman-resources/src/main/resources/yangman/views/rightpanel/request-header.tpl.html [new file with mode: 0644]
modules/yangman-resources/src/main/resources/yangman/views/root.tpl.html [new file with mode: 0644]
modules/yangman-resources/src/main/resources/yangman/yangman.filters.js [new file with mode: 0644]
modules/yangman-resources/src/main/resources/yangman/yangman.less [new file with mode: 0644]
modules/yangman-resources/src/main/resources/yangman/yangman.module.js [new file with mode: 0644]
modules/yangui-resources/pom.xml
modules/yangui-resources/src/main/resources/yangui/assets/js/codemirror/AUTHORS [deleted file]
modules/yangui-resources/src/main/resources/yangui/assets/js/codemirror/CONTRIBUTING.md [deleted file]
modules/yangui-resources/src/main/resources/yangui/assets/js/codemirror/LICENSE [deleted file]
modules/yangui-resources/src/main/resources/yangui/assets/js/codemirror/README.md [deleted file]
modules/yangui-resources/src/main/resources/yangui/main.js
modules/yangui-resources/src/main/resources/yangui/yangui.less
modules/yangui-resources/src/main/resources/yangui/yangui.module.js
modules/yangvisualizer-resources/pom.xml
pom.xml

index cf78d141ae88aedf3fc1347294fb01ac93912b5f..71fd842ffab627206259b96860ee6b8d18202eab 100644 (file)
@@ -40,3 +40,4 @@ target/
 # virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml
 hs_err_pid*
 dlux-web/node
+dlux-web/src/LICENSE
index 960e3807c621e897482f3d0dd35917cbfa2cce0b..803043c498171300c9aa795cbf0b4e4807b35ddd 100644 (file)
@@ -5,7 +5,7 @@
     <parent>
         <groupId>org.opendaylight.controller.archetypes</groupId>
         <artifactId>archetypes-parent</artifactId>
-        <version>0.4.0-SNAPSHOT</version>
+        <version>0.5.0-SNAPSHOT</version>
         <relativePath/>
     </parent>
 
index c447205e5a2fa68ced337d261e5ee06bf5f6b810..6827abb66e62838d5c83f9cdd9a166f96a353bc8 100644 (file)
@@ -13,7 +13,7 @@
     <properties>
         <osgi.core.version>5.0.0</osgi.core.version>
         <apache.felix.compendium>1.4.0</apache.felix.compendium>
-        <dlux.loader.version>0.4.0-SNAPSHOT</dlux.loader.version>
+        <dlux.loader.version>0.5.0-SNAPSHOT</dlux.loader.version>
     </properties>
 
 
index c4d7eb3406c43036fbbfc095e72a42c542321c9d..2b8e30395b1fb58285a5792140298d407105f036 100644 (file)
@@ -4,7 +4,7 @@
   <parent>
     <groupId>org.opendaylight.dlux</groupId>
     <artifactId>bundles</artifactId>
-    <version>0.4.0-SNAPSHOT</version>
+    <version>0.5.0-SNAPSHOT</version>
     <relativePath>../</relativePath>
   </parent>
   <groupId>org.opendaylight.dlux</groupId>
@@ -52,7 +52,6 @@
      <plugin>
         <groupId>org.apache.maven.plugins</groupId>
         <artifactId>maven-dependency-plugin</artifactId>
-        <version>2.6</version>
         <executions>
      <!--loader Resources-->
           <execution>
index 3736cc6c589a745311d7411654a1f2b272454061..7e99347513110cec79caa9d669f0992265798938 100644 (file)
@@ -4,7 +4,7 @@
   <parent>
     <groupId>org.opendaylight.dlux</groupId>
     <artifactId>bundles</artifactId>
-    <version>0.4.0-SNAPSHOT</version>
+    <version>0.5.0-SNAPSHOT</version>
     <relativePath>../</relativePath>
   </parent>
   <groupId>org.opendaylight.dlux</groupId>
@@ -65,7 +65,6 @@
      <plugin>
         <groupId>org.apache.maven.plugins</groupId>
         <artifactId>maven-dependency-plugin</artifactId>
-        <version>2.6</version>
         <executions>
      <!--loader Resources-->
           <execution>
index b8ab605bb93aa27ee88b94fc4b937e959fe7728e..8ddaae2dd64318bf6e3b4393ab71da05a287c66d 100644 (file)
@@ -4,7 +4,7 @@
   <parent>
     <groupId>org.opendaylight.dlux</groupId>
     <artifactId>bundles</artifactId>
-    <version>0.4.0-SNAPSHOT</version>
+    <version>0.5.0-SNAPSHOT</version>
     <relativePath>../</relativePath>
   </parent>
   <groupId>org.opendaylight.dlux</groupId>
@@ -52,7 +52,6 @@
      <plugin>
         <groupId>org.apache.maven.plugins</groupId>
         <artifactId>maven-dependency-plugin</artifactId>
-        <version>2.6</version>
         <executions>
      <!--loader Resources-->
           <execution>
index 5d56f49e7905ba5f382f5bc46d8cb7bc6d49083f..6de257ae62e0bf1f7a0fb494ef7150fa6a12c2e4 100644 (file)
@@ -4,7 +4,7 @@
   <parent>
     <groupId>org.opendaylight.dlux</groupId>
     <artifactId>bundles</artifactId>
-    <version>0.4.0-SNAPSHOT</version>
+    <version>0.5.0-SNAPSHOT</version>
     <relativePath>../</relativePath>
   </parent>
   <groupId>org.opendaylight.dlux</groupId>
@@ -52,7 +52,6 @@
      <plugin>
         <groupId>org.apache.maven.plugins</groupId>
         <artifactId>maven-dependency-plugin</artifactId>
-        <version>2.6</version>
         <executions>
      <!--loader Resources-->
           <execution>
index 1013c698ef73594ba19b4256fd8b27c8eca5667e..96bf9c9e518323d1a19bf1747a823cc9c5402239 100644 (file)
@@ -4,7 +4,7 @@
   <parent>
     <groupId>org.opendaylight.dlux</groupId>
     <artifactId>bundles</artifactId>
-    <version>0.4.0-SNAPSHOT</version>
+    <version>0.5.0-SNAPSHOT</version>
     <relativePath>../</relativePath>
   </parent>
   <groupId>org.opendaylight.dlux</groupId>
@@ -52,7 +52,6 @@
      <plugin>
         <groupId>org.apache.maven.plugins</groupId>
         <artifactId>maven-dependency-plugin</artifactId>
-        <version>2.6</version>
         <executions>
      <!--loader Resources-->
           <execution>
index dd629c5e3eedd08f30ed6709541e92d6dd93c8ba..d1594f0267f0d03bdbeb3d5b4a09213a6d3266dc 100644 (file)
@@ -4,7 +4,7 @@
   <parent>
     <groupId>org.opendaylight.dlux</groupId>
     <artifactId>bundles</artifactId>
-    <version>0.4.0-SNAPSHOT</version>
+    <version>0.5.0-SNAPSHOT</version>
     <relativePath>../</relativePath>
   </parent>
   <groupId>org.opendaylight.dlux</groupId>
@@ -52,7 +52,6 @@
       <plugin>
         <groupId>org.apache.maven.plugins</groupId>
         <artifactId>maven-dependency-plugin</artifactId>
-        <version>2.6</version>
         <executions>
      <!--loader Resources-->
           <execution>
index 867c97da47a7e37b73e6634ecbff74e0769755e7..7f3e1f7ead375c5460e10ab00bc1d79930838d8d 100644 (file)
@@ -4,7 +4,7 @@
   <parent>
     <groupId>org.opendaylight.dlux</groupId>
     <artifactId>bundles</artifactId>
-    <version>0.4.0-SNAPSHOT</version>
+    <version>0.5.0-SNAPSHOT</version>
     <relativePath>../</relativePath>
   </parent>
   <groupId>org.opendaylight.dlux</groupId>
@@ -52,7 +52,6 @@
      <plugin>
         <groupId>org.apache.maven.plugins</groupId>
         <artifactId>maven-dependency-plugin</artifactId>
-        <version>2.6</version>
         <executions>
      <!--loader Resources-->
           <execution>
index a1fbe3df65b68fe345d15d20a4f9016586f4d66d..7427988c05d26c0ce37a8dfd669c0f7075d6b287 100644 (file)
@@ -12,7 +12,7 @@
   <parent>
     <groupId>org.opendaylight.dlux</groupId>
     <artifactId>dlux-parent</artifactId>
-    <version>0.4.0-SNAPSHOT</version>
+    <version>0.5.0-SNAPSHOT</version>
     <relativePath>../</relativePath>
   </parent>
 
@@ -34,6 +34,7 @@
     <module>node</module>
     <module>topology</module>
     <module>yangui</module>
+    <module>yangman</module>
     <module>yangutils</module>
     <module>yangvisualizer</module>
     <module>sigmatopology</module>
index 62fd0dd922a1f54d727d0d19f90eb8d02bf2aed9..d730fb3318a0603395eb2be5faf37c7f1a8859fb 100644 (file)
@@ -4,7 +4,7 @@
   <parent>
     <groupId>org.opendaylight.dlux</groupId>
     <artifactId>bundles</artifactId>
-    <version>0.4.0-SNAPSHOT</version>
+    <version>0.5.0-SNAPSHOT</version>
     <relativePath>../</relativePath>
   </parent>
   <groupId>org.opendaylight.dlux</groupId>
@@ -52,7 +52,6 @@
      <plugin>
         <groupId>org.apache.maven.plugins</groupId>
         <artifactId>maven-dependency-plugin</artifactId>
-        <version>2.6</version>
         <executions>
      <!--loader Resources-->
           <execution>
index 03917838e5f430b35edee34c147c246eec9a00bd..96757d328ffcb99104f0d11ca92889d8470431df 100644 (file)
@@ -4,7 +4,7 @@
   <parent>
     <groupId>org.opendaylight.dlux</groupId>
     <artifactId>bundles</artifactId>
-    <version>0.4.0-SNAPSHOT</version>
+    <version>0.5.0-SNAPSHOT</version>
     <relativePath>../</relativePath>
   </parent>
   <groupId>org.opendaylight.dlux</groupId>
@@ -52,7 +52,6 @@
      <plugin>
         <groupId>org.apache.maven.plugins</groupId>
         <artifactId>maven-dependency-plugin</artifactId>
-        <version>2.6</version>
         <executions>
      <!--loader Resources-->
           <execution>
index 275bd1ed5fa2707474a7309910a9ecc0f05b967a..46082f453a27248467853d3f139b4a9946c7c350 100644 (file)
@@ -4,7 +4,7 @@
   <parent>
     <groupId>org.opendaylight.dlux</groupId>
     <artifactId>bundles</artifactId>
-    <version>0.4.0-SNAPSHOT</version>
+    <version>0.5.0-SNAPSHOT</version>
     <relativePath>../</relativePath>
   </parent>
   <groupId>org.opendaylight.dlux</groupId>
@@ -52,7 +52,6 @@
      <plugin>
         <groupId>org.apache.maven.plugins</groupId>
         <artifactId>maven-dependency-plugin</artifactId>
-        <version>2.6</version>
         <executions>
      <!--loader Resources-->
           <execution>
diff --git a/bundles/yangman/pom.xml b/bundles/yangman/pom.xml
new file mode 100644 (file)
index 0000000..79cfd70
--- /dev/null
@@ -0,0 +1,97 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<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.opendaylight.dlux</groupId>
+    <artifactId>bundles</artifactId>
+    <version>0.5.0-SNAPSHOT</version>
+    <relativePath>../</relativePath>
+  </parent>
+  <groupId>org.opendaylight.dlux</groupId>
+  <artifactId>dlux.yangman</artifactId>
+  <packaging>bundle</packaging>
+  <dependencies>
+    <dependency>
+      <groupId>org.osgi</groupId>
+      <artifactId>org.osgi.core</artifactId>
+    </dependency>
+    <dependency>
+      <groupId>org.osgi</groupId>
+      <artifactId>org.osgi.compendium</artifactId>
+    </dependency>
+    <dependency>
+      <groupId>org.apache.felix</groupId>
+      <artifactId>org.osgi.compendium</artifactId>
+      <version>${apache.felix.osgi.compendium.version}</version>
+    </dependency>
+    <dependency>
+      <groupId>org.slf4j</groupId>
+      <artifactId>jcl-over-slf4j</artifactId>
+    </dependency>
+    <dependency>
+      <groupId>org.opendaylight.dlux</groupId>
+      <artifactId>loader</artifactId>
+        <version>${project.version}</version>
+    </dependency>
+     <dependency>
+      <groupId>org.opendaylight.dlux</groupId>
+      <artifactId>dlux.yangman.resources</artifactId>
+      <version>${yangman.resources.version}</version>
+    </dependency>
+  </dependencies>
+ <build>
+   <resources>
+      <resource>
+        <directory>target/generated-resources</directory>
+      </resource>
+      <resource>
+        <directory>src/main/resources</directory>
+      </resource>
+    </resources>
+    <plugins>
+     <plugin>
+        <groupId>org.apache.maven.plugins</groupId>
+        <artifactId>maven-dependency-plugin</artifactId>
+        <executions>
+     <!--loader Resources-->
+          <execution>
+            <id>unpack-loader-resources</id>
+            <goals>
+              <goal>unpack-dependencies</goal>
+            </goals>
+            <phase>generate-resources</phase>
+            <configuration>
+              <outputDirectory>${project.build.directory}/generated-resources</outputDirectory>
+              <groupId>org.opendaylight.dlux</groupId>
+              <includeArtifactIds>dlux.yangman.resources</includeArtifactIds>
+              <excludes>META-INF\/**</excludes>
+              <excludeTransitive>true</excludeTransitive>
+              <ignorePermissions>false</ignorePermissions>
+            </configuration>
+          </execution>
+        </executions>
+      </plugin>
+      <plugin>
+        <groupId>org.apache.felix</groupId>
+        <artifactId>maven-bundle-plugin</artifactId>
+        <extensions>true</extensions>
+        <configuration>
+          <instructions>
+            <Import-Package>org.osgi.service.http,
+                            org.osgi.framework;version="1.0.0",
+                            org.opendaylight.dlux.loader,
+                            org.slf4j
+            </Import-Package>
+            <Export-Package></Export-Package>
+          </instructions>
+        </configuration>
+      </plugin>
+    </plugins>
+  </build>
+  <scm>
+    <connection>scm:git:ssh://git.opendaylight.org:29418/dlux.git</connection>
+    <developerConnection>scm:git:ssh://git.opendaylight.org:29418/dlux.git</developerConnection>
+    <tag>HEAD</tag>
+    <url>https://wiki.opendaylight.org/view/OpenDaylight_dlux:Main</url>
+  </scm>
+</project>
diff --git a/bundles/yangman/src/main/resources/OSGI-INF/blueprint/blueprint.xml b/bundles/yangman/src/main/resources/OSGI-INF/blueprint/blueprint.xml
new file mode 100644 (file)
index 0000000..a3c8757
--- /dev/null
@@ -0,0 +1,13 @@
+<blueprint xmlns="http://www.osgi.org/xmlns/blueprint/v1.0.0">
+    <reference id="httpService" availability="mandatory" activation="eager" interface="org.osgi.service.http.HttpService"/>
+    <reference id="loader" availability="mandatory" activation="eager" interface="org.opendaylight.dlux.loader.DluxModuleLoader"/>
+    <bean id="bundle" init-method="initialize" destroy-method="clean" class="org.opendaylight.dlux.loader.DluxModule">
+       <property name="httpService" ref="httpService"/>
+       <property name="loader" ref="loader"/>
+       <property name="moduleName" value="yangman"/>
+       <property name="url" value="/src/app/yangman"/>
+        <property name="directory" value="/yangman"/>
+       <property name="requireJs" value="app/yangman/main"/>
+       <property name="angularJs" value="app.yangman"/>
+    </bean>
+</blueprint>
index 9b97d37f57a2c2367ecea4ef88fa2cda8c69ad73..eba9520e2d8343f29e10f354c192b9dc9f04def2 100644 (file)
@@ -4,7 +4,7 @@
   <parent>
     <groupId>org.opendaylight.dlux</groupId>
     <artifactId>bundles</artifactId>
-    <version>0.4.0-SNAPSHOT</version>
+    <version>0.5.0-SNAPSHOT</version>
     <relativePath>../</relativePath>
   </parent>
   <groupId>org.opendaylight.dlux</groupId>
@@ -52,7 +52,6 @@
      <plugin>
         <groupId>org.apache.maven.plugins</groupId>
         <artifactId>maven-dependency-plugin</artifactId>
-        <version>2.6</version>
         <executions>
      <!--loader Resources-->
           <execution>
index 445f729f7165adb2ed73fd7f1f77ed54d844c31c..11cfdee948f0bc2d7c45f21ebc378e122850bced 100644 (file)
@@ -4,7 +4,7 @@
   <parent>
     <groupId>org.opendaylight.dlux</groupId>
     <artifactId>bundles</artifactId>
-    <version>0.4.0-SNAPSHOT</version>
+    <version>0.5.0-SNAPSHOT</version>
     <relativePath>../</relativePath>
   </parent>
   <groupId>org.opendaylight.dlux</groupId>
@@ -52,7 +52,6 @@
      <plugin>
         <groupId>org.apache.maven.plugins</groupId>
         <artifactId>maven-dependency-plugin</artifactId>
-        <version>2.6</version>
         <executions>
      <!--loader Resources-->
           <execution>
index e9762524a36db7a22b9842ee2acc437f7bfd2a8e..6c173dd42d9bdb8855e28589b8044230589f35ae 100644 (file)
@@ -4,7 +4,7 @@
   <parent>
     <groupId>org.opendaylight.dlux</groupId>
     <artifactId>bundles</artifactId>
-    <version>0.4.0-SNAPSHOT</version>
+    <version>0.5.0-SNAPSHOT</version>
     <relativePath>../</relativePath>
   </parent>
   <groupId>org.opendaylight.dlux</groupId>
@@ -52,7 +52,6 @@
      <plugin>
         <groupId>org.apache.maven.plugins</groupId>
         <artifactId>maven-dependency-plugin</artifactId>
-        <version>2.6</version>
         <executions>
      <!--loader Resources-->
           <execution>
index 15815e4a16ac82a61a0b0b2a0f139b720e347514..fc645247fd086f018080ec29f168aceb3cfadf33 100644 (file)
@@ -3,13 +3,16 @@
   "version": "0.2.0",
   "dependencies": {
     "angular": "~1.4.0",
+    "angular-resource": "~1.4.0",
+    "angular-cookies": "~1.4.0",
+    "angular-sanitize": "~1.4.0",
+    "angular-messages": "~1.4.0",
+    "angular-animate": "~1.4.0",
+    "angular-aria": "~1.4.0",
     "json3": "~3.2.4",
     "jquery": "~1.9.1",
     "jquery-ui": "1.11.1",
     "es5-shim": "~2.0.8",
-    "angular-resource": "~1.4.0",
-    "angular-cookies": "~1.4.0",
-    "angular-sanitize": "~1.4.0",
     "angular-ui-date": "~0.0.11",
     "requirejs": "~2.1.14",
     "font-awesome": "~4.0.3",
     "angular-ui-router": "~0.2.10",
     "angular-ui-utils": "~0.0.3",
     "d3": "~3.3.2",
-    "restangular": "1.2.1",
+    "restangular": "1.4.0",
     "angular-ui-select2": "~0.0.5",
     "underscore": "~1.8.3",
     "underscore.string": "~3.2.1",
     "select2": "^3.3.2",
     "select2-bootstrap-css": "~1.2.5",
     "footable": "2.0.1",
-    "angular-translate": "2.2.0",
-    "angular-translate-loader-static-files": "2.2.0",
     "vis": "2.0.0",
     "sigma": "https://github.com/jacomyal/sigma.js/releases/download/v1.0.3/release-v1.0.3.zip",
     "ng-slider": "2.2.2",
-    "ng-tiny-scrollbar": "~0.9.0",
     "zeroclipboard": "~2.2.0",
     "ng-clip": "~0.2.6",
-    "angular-translate-loader-partial": "~2.7.2"
+    "angular-translate": "~2.7.2",
+    "angular-translate-loader-static-files": "~2.7.2",
+    "angular-translate-loader-partial": "~2.7.2",
+    "angular-material": "~1.0.8",
+    "material-design-icons": "~2.2.3"
   },
   "devDependencies": {
     "angular": "~1.4.0",
@@ -48,6 +52,7 @@
   "resolutions": {
     "angular": "~1.4.0",
     "angular-translate": "~2.7.2",
+    "angular-animate": "~1.4.0",
     "select2": "^3.3.2"
   }
 }
index 7dd95857c732fc30a3f043d86ee97e53aa81658c..9b487f090117fe58861868a97a542a3bba6a6782 100644 (file)
@@ -9,7 +9,7 @@ module.exports = {
    */\r
   build_dir: 'build',\r
   compile_dir: 'target/generated-resources/pages',\r
-  \r
+\r
   /**\r
    * This is a collection of file patterns that refer to our app code (the\r
    * stuff in `src/`). These file paths are used in the configuration of\r
@@ -24,7 +24,7 @@ module.exports = {
     jsunit: [ 'src/**/*.spec.js' ],\r
     js_common: [ 'src/common/**/*.js', '!src/common/**/*.spec.js', '!src/common/assets/**/*.js'  ],\r
     js_app: [ 'src/app/**/*.js', '!src/app/**/*.spec.js', '!src/app/assets/**/*.js'  ],\r
-    app_assets: [ '! src/app/yangui/assets/js/**/*.js' ],\r
+    app_assets: [ '! src/app/yangui/assets/js/**/*.js', '! src/app/yangman/assets/js/**/*.js' ],\r
 \r
     atpl: [ 'src/app/**/*.tpl.html' ],\r
     ctpl: [ 'src/common/**/*.tpl.html' ],\r
@@ -101,6 +101,10 @@ module.exports = {
       'vendor/ng-clip/src/ngClip.js',\r
       'vendor/zeroclipboard/dist/ZeroClipboard.js',\r
       'vendor/angular-translate-loader-partial/angular-translate-loader-partial.js',\r
+      'vendor/angular-animate/angular-animate.min.js',\r
+      'vendor/angular-aria/angular-aria.min.js',\r
+      'vendor/angular-material/angular-material.min.js',\r
+      'vendor/angular-messages/angular-messages.min.js',\r
     ],\r
     css: [\r
     'vendor/ng-grid/ng-grid.min.css',\r
@@ -109,8 +113,9 @@ module.exports = {
     'vendor/footable/css/footable.core.min.css',\r
     'vendor/footable/css/footable.standalone.min.css',\r
     'vendor/vis/dist/vis.min.css',\r
-    'vendor/ng-slider/dist/css/ng-slider.min.css'\r
-\r
+    'vendor/ng-slider/dist/css/ng-slider.min.css',\r
+    'vendor/angular-material/angular-material.css',\r
+    'vendor/material-design-icons/iconfont/*',\r
     ],\r
     images: [\r
     'vendor/select2/select2.png',\r
@@ -118,11 +123,12 @@ module.exports = {
     'vendor/select2/select2x2.png'\r
     ],\r
     assets: [\r
-    'vendor/zeroclipboard/dist/ZeroClipboard.swf'\r
+    'vendor/zeroclipboard/dist/ZeroClipboard.swf',\r
     ],\r
     font: [\r
       'vendor/font-awesome/font/*',\r
-      'vendor/footable/css/fonts/*'\r
+      'vendor/footable/css/fonts/*',\r
+\r
     ]\r
   }\r
 };\r
index 62f97b2a29f01ef0cee99db9a989557154348db9..bf9ee86ce45202ca93aee76ffa8f6f4d4de73414 100644 (file)
@@ -4,7 +4,7 @@
   <parent>\r
     <groupId>org.opendaylight.dlux</groupId>\r
     <artifactId>dlux-parent</artifactId>\r
-    <version>0.4.0-SNAPSHOT</version>\r
+    <version>0.5.0-SNAPSHOT</version>\r
     <relativePath>..</relativePath>\r
   </parent>\r
 \r
         <artifactId>dlux.yangui.resources</artifactId>\r
         <version>${yangui.resources.version}</version>\r
     </dependency>\r
+    <dependency>\r
+        <groupId>org.opendaylight.dlux</groupId>\r
+        <artifactId>dlux.yangman.resources</artifactId>\r
+        <version>${yangman.resources.version}</version>\r
+    </dependency>\r
     <dependency>\r
         <groupId>org.opendaylight.dlux</groupId>\r
         <artifactId>dlux.yangvisualizer.resources</artifactId>\r
                          <include>app/routingConfig.js</include>\r
                       <include>app/node/</include>\r
                       <include>app/yangui/</include>\r
+                      <include>app/yangman/</include>\r
                       <include>app/yangvisualizer/</include>\r
                       <include>app/topology/</include>\r
                       <include>app/core/</include>\r
         <plugin>\r
           <groupId>org.apache.maven.plugins</groupId>\r
           <artifactId>maven-dependency-plugin</artifactId>\r
-          <version>2.6</version>\r
           <executions>\r
          <!--src/app/ Resources-->\r
             <execution>\r
                 <includeArtifactIds>\r
                   dlux.node.resources,\r
                   dlux.yangui.resources,\r
+                  dlux.yangman.resources,\r
                   dlux.yangvisualizer.resources,\r
                   dlux.topology.resources,\r
                   dlux.core.resources,\r
index f683d5badbe913df096f58a0af5c1f3080f74709..083787eb02939aa41a82c00dee4de2d20d561fc3 100644 (file)
@@ -49,12 +49,6 @@ li.active {
        color: white;
 }
 
-.main input[type="text"] {
-       background-color: #58595B;
-       color: white;
-}
-
-
 .select2-choice, .select2-choices {
        background-color: #58595B !important;
 }
@@ -68,7 +62,7 @@ li.active {
 .btn-orange {
        background-color: orange;
 }
-h1, h2, h3, h4, h5, h6, span {
+h1, h2, h3, h4, h5, h6 {
        color: white;
 }
 
@@ -111,7 +105,7 @@ h1, h2, h3, h4, h5, h6, span {
 }
 
 .select2-choice {
-       border: 1px solid #939598 !important;   
+       border: 1px solid #939598 !important;
 }
 
 #red {
@@ -133,13 +127,13 @@ h1, h2, h3, h4, h5, h6, span {
 .navbar {
        border-bottom: none !important;
        background-color: black !important;
-} 
+}
 @media all and (max-width: 462px) {
-       
+
        .navbar {
        border-bottom: none !important;
        background-color: #F3F3F4 !important;
-} 
+}
    #page_logo {
                display: none;
    }
index 118958293f37126208f62e35b5c943008db86cf3..ace5fdc436b709411d796ba212d45e83ff2cf6b8 100644 (file)
@@ -65,6 +65,9 @@ h2 {
   color: #666;\r
 }\r
 \r
+.main {\r
+  position: relative;\r
+}\r
 \r
 /**\r
  * Navigation\r
@@ -114,7 +117,7 @@ h2 {
 \r
 /**\r
  * Now that all app-wide styles have been applied, we can load the styles for\r
- * all the submodules and components we are using. \r
+ * all the submodules and components we are using.\r
  *\r
  * TODO: In a later version of this boilerplate, I'd like to automate this.\r
  */\r
@@ -129,3 +132,8 @@ h2 {
 @import '../common/login/login.less';\r
 @import '../common/topbar/topbar.less';\r
 @import '../app/topology/topology.less';\r
+@import '../app/yangman/yangman.less';\r
+@import '../assets/js/codemirror/lib/codemirror.less';\r
+@import '../assets/js/codemirror/theme/eclipse.less';\r
+@import '../assets/js/codemirror/theme/eclipse-disabled.less';\r
+@import '../assets/js/codemirror/addon/hint/show-hint.less';\r
index 1628c44ae5f6e94d3ae489936b663f8f174fa626..f5ce7c8d4529074d27f346a7be48bffd794c90fe 100644 (file)
@@ -4,30 +4,30 @@
   <parent>
     <groupId>org.opendaylight.odlparent</groupId>
     <artifactId>features-parent</artifactId>
-    <version>1.7.0-SNAPSHOT</version>
+    <version>1.8.0-SNAPSHOT</version>
     <relativePath/>
   </parent>
   <groupId>org.opendaylight.dlux</groupId>
   <artifactId>features-dlux</artifactId>
-  <version>0.4.0-SNAPSHOT</version>
+  <version>0.5.0-SNAPSHOT</version>
   <name>DLUX - Features </name>
   <packaging>jar</packaging>
 
   <properties>
     <features.file>features.xml</features.file>
-    <restconf.version>1.4.0-SNAPSHOT</restconf.version>
+    <restconf.version>1.5.0-SNAPSHOT</restconf.version>
   </properties>
 
   <dependencies>
       <dependency>
          <groupId>org.opendaylight.odlparent</groupId>
          <artifactId>features-test</artifactId>
-         <version>1.7.0-SNAPSHOT</version>
+         <version>1.8.0-SNAPSHOT</version>
       </dependency>
       <dependency>
          <groupId>org.opendaylight.controller</groupId>
          <artifactId>opendaylight-karaf-empty</artifactId>
-         <version>1.7.0-SNAPSHOT</version>
+         <version>1.8.0-SNAPSHOT</version>
          <type>zip</type>
       </dependency>
       <dependency>
           <artifactId>dlux.yangui</artifactId>
           <version>${project.version}</version>
       </dependency>
+      <dependency>
+          <groupId>org.opendaylight.dlux</groupId>
+          <artifactId>dlux.yangman</artifactId>
+          <version>${project.version}</version>
+      </dependency>
       <dependency>
           <groupId>org.opendaylight.dlux</groupId>
           <artifactId>dlux.common.yangutils</artifactId>
index 25b0eb5cdc2621fea87f1cb774ec5b23a8beceef..8ee80f59b6ee5669ccb65206196e1a1fde66a90b 100644 (file)
         <bundle>mvn:org.opendaylight.dlux/dlux.common.sigmatopology/{{VERSION}}</bundle>
     </feature>
 
+    <feature name="odl-dlux-yangman" version='${project.version}' description="Enable Yangman in Opendaylight dlux">
+        <feature>odl-dlux-core</feature>
+        <feature version="${restconf.version}">odl-mdsal-apidocs</feature>
+        <bundle>mvn:org.opendaylight.dlux/dlux.yangman/{{VERSION}}</bundle>
+        <bundle>mvn:org.opendaylight.dlux/dlux.common.yangutils/{{VERSION}}</bundle>
+        <bundle>mvn:org.opendaylight.dlux/dlux.common.sigmatopology/{{VERSION}}</bundle>
+    </feature>
+
        <feature name="odl-dlux-yangvisualizer" version='${project.version}' description="Enable Yang visualizer in Opendaylight dlux">
         <feature>odl-dlux-core</feature>
         <bundle>mvn:org.opendaylight.dlux/dlux.yangvisualizer/{{VERSION}}</bundle>
index d525fd9587e6853522dda08babb2a0a1b3232dc2..6f848a8f884456e845f5f32a69b7284e8008bcf6 100644 (file)
@@ -4,7 +4,7 @@
   <parent>
     <groupId>org.opendaylight.dlux</groupId>
     <artifactId>dlux-parent</artifactId>
-    <version>0.4.0-SNAPSHOT</version>
+    <version>0.5.0-SNAPSHOT</version>
     <relativePath>../../</relativePath>
   </parent>
   <artifactId>loader</artifactId>
index 01320fec41f8d08a096cc1abc052e4d092f97acf..8dbd3cef3b7691c5155f0a319156a4e8c773f0e3 100644 (file)
@@ -4,7 +4,7 @@
   <parent>
     <groupId>org.opendaylight.dlux</groupId>
     <artifactId>dlux-parent</artifactId>
-    <version>0.4.0-SNAPSHOT</version>
+    <version>0.5.0-SNAPSHOT</version>
     <relativePath>../../</relativePath>
   </parent>
   <artifactId>loader.implementation</artifactId>
index 2e370c554682abeb6a109bdcab7a0e0ca36d89a4..7a543faa21f5b94570ada3f73189bd9bf96f81c1 100644 (file)
@@ -12,7 +12,7 @@
   <parent>
     <groupId>org.opendaylight.dlux</groupId>
     <artifactId>dlux-parent</artifactId>
-    <version>0.4.0-SNAPSHOT</version>
+    <version>0.5.0-SNAPSHOT</version>
     <relativePath>../../</relativePath>
   </parent>
 
index 59e163de071660ef76c08c32b4d8faaf3b4f2ad4..42068aade95a47961d397986648324298726e0aa 100644 (file)
@@ -12,7 +12,7 @@
   <parent>
     <groupId>org.opendaylight.dlux</groupId>
     <artifactId>dlux-parent</artifactId>
-    <version>0.4.0-SNAPSHOT</version>
+    <version>0.5.0-SNAPSHOT</version>
     <relativePath>../../</relativePath>
   </parent>
 
index a09028caaf95f80f7a068ec7e127a57c80b989c3..47583a55b76a54a5e74b94fe31b15d93c3c4895c 100644 (file)
@@ -12,7 +12,7 @@
   <parent>
     <groupId>org.opendaylight.dlux</groupId>
     <artifactId>dlux-parent</artifactId>
-    <version>0.4.0-SNAPSHOT</version>
+    <version>0.5.0-SNAPSHOT</version>
     <relativePath>../../</relativePath>
   </parent>
 
index 97faee48533494a6812a75232bd6fedb1e959fd2..0c57c52360371531a8a0214563fb895c3444e4b2 100644 (file)
@@ -14,4 +14,4 @@
     </div>
   </div><!-- /.page-content -->
 </div>
-</div><!-- /.main-content -->
+<!-- /.main-content -->
index 5ff53a76e48694ddab00601da811bad54d32baf7..ef2087be4f592c38f966b79ea9a1bf697fa759f2 100644 (file)
@@ -12,7 +12,7 @@
   <parent>
     <groupId>org.opendaylight.dlux</groupId>
     <artifactId>dlux-parent</artifactId>
-    <version>0.4.0-SNAPSHOT</version>
+    <version>0.5.0-SNAPSHOT</version>
     <relativePath>../../</relativePath>
   </parent>
 
index 72fd78294143453ad2c901bc084215464bfbdd94..c077c8f2f1d0ae9b6b66b877adcbb3c29dd51ebf 100644 (file)
@@ -12,7 +12,7 @@
   <parent>
     <groupId>org.opendaylight.dlux</groupId>
     <artifactId>dlux-parent</artifactId>
-    <version>0.4.0-SNAPSHOT</version>
+    <version>0.5.0-SNAPSHOT</version>
     <relativePath>../../</relativePath>
   </parent>
 
index ec6efbc922034ba683a39e298eef9405b6bb3f6c..e22014a8992de47a574a968cfc02b487e94e1342 100644 (file)
@@ -1,19 +1,19 @@
 #page-wrapper {
-       min-height: 0px !important; 
+  min-height: 0px !important;
 }
 
 .btn-orange {
-       background-color: orange;
+  background-color: orange;
 }
 
 .error {
-       color: Red;
+  color: Red;
 }
 
-html, body, #wrapper, #page-wrapper {
-       height: 100%;
+html, body, #page-wrapper, #main-content-container{
+  height: 100%;
 }
 
 .footable {
-       margin-top: 25px;
+  margin-top: 25px;
 }
\ No newline at end of file
index ef7b28fa2ef5b1b0e950c9e6b47560ad4abd73dd..98e9bfaab2cfb197242c63ffda21e9873b3ddf61 100644 (file)
@@ -12,7 +12,7 @@
   <parent>
     <groupId>org.opendaylight.dlux</groupId>
     <artifactId>dlux-parent</artifactId>
-    <version>0.4.0-SNAPSHOT</version>
+    <version>0.5.0-SNAPSHOT</version>
     <relativePath>../../</relativePath>
   </parent>
 
index 18bdb28818b658e10f07dc8bba69f3a94ce21cc7..dffe9450f33317882558449e59f883d6c046db7b 100644 (file)
@@ -12,7 +12,7 @@
   <parent>
     <groupId>org.opendaylight.dlux</groupId>
     <artifactId>dlux-parent</artifactId>
-    <version>0.4.0-SNAPSHOT</version>
+    <version>0.5.0-SNAPSHOT</version>
     <relativePath>../../</relativePath>
   </parent>
 
index e085e907a44deae0a9f3d9ea3e518932f112b751..e7cb125e5e1800a24bc9978cce3372002156b5f4 100644 (file)
@@ -12,7 +12,7 @@
   <parent>
     <groupId>org.opendaylight.dlux</groupId>
     <artifactId>dlux-parent</artifactId>
-    <version>0.4.0-SNAPSHOT</version>
+    <version>0.5.0-SNAPSHOT</version>
     <relativePath>../../</relativePath>
   </parent>
 
index 69e4a8be982ff39333660b53a07b9944e17b1e63..4e47efac95cbdb15fb69e140081461a40088229d 100644 (file)
@@ -23,6 +23,58 @@ function () {
         ALLOWED_LEAF_TYPES_FOR_FILTER: ['string', 'uint32', 'uint8', 'decimal64', 'int16', 'int32', 'int64', 'int8',
                                         'uint16', 'uint64', 'union', 'bits', 'leafref', 'identityref'],
         ALLOWED_NODE_TYPES_FOR_FILTER: ['case', 'choice', 'container', 'input', 'leaf', 'output', 'rpc'],
+        DISPLAY_TYPE_REQ_DATA: 'req-data',
+        DISPLAY_TYPE_FORM: 'form',
+        DATA_STORE_CONFIG: 'config',
+        DATA_STORE_OPERATIONAL: 'operational',
+        DATA_STORE_OPERATIONS: 'operations',
+        NODE_RPC: 'rpc',
+        OPERATION_GET: 'GET',
+        OPERATION_PUT: 'PUT',
+        OPERATION_DELETE: 'DELETE',
+        OPERATION_POST: 'POST',
+        REQUEST_DATA_TYPE_RECEIVED: 'RECEIVED',
+        ICON_EXPAND_ADD: 'add',
+        ICON_COLLAPSE_REMOVE: 'remove',
+        ICON_KEYBOARD_ARROW_RIGHT: 'keyboard_arrow_right',
+        EXPAND_LEVEL_THREE: '3',
+        COLLECTION_CHECK_ARRAY: ['sentData', 'receivedData', 'path', 'collection', 'method', 'status', 'name'],
+        EV_REFRESH_LIST_INDEX: 'EV_REFRESH_LIST_INDEX',
+        YANGMAN_DISABLE_ADDING_LIST_ELEMENT: 'YANGMAN_DISABLE_ADDING_LIST_ELEMENT',
+        YANGMAN_MODULE_D_INIT: 'YANGMAN_MODULE_D_INIT',
+        YANGMAN_GET_API_TREE_DATA: 'YANGMAN_GET_API_TREE_DATA',
+        YANGMAN_SET_API_TREE_DATA: 'YANGMAN_SET_API_TREE_DATA',
+        YANGMAN_SET_LOADING_BOX: 'YANGMAN_SET_LOADING_BOX',
+        YANGMAN_SHOW_TOAST: 'YANGMAN_SHOW_TOAST',
+        YANGMAN_SET_MODULE_LIST_TITLE: 'YANGMAN_SET_MODULE_LIST_TITLE',
+        YANGMAN_SET_CODEMIRROR_DATA: 'YANGMAN_SET_CODEMIRROR_DATA_',
+        YANGMAN_GET_CODEMIRROR_DATA: 'YANGMAN_GET_CODEMIRROR_DATA_',
+        SET_SEL_OPERATIONS: 'SET_SEL_OPERATIONS',
+        YANGMAN_HEADER_INIT: 'YANGMAN_HEADER_INIT',
+        YANGMAN_FILL_NODE_FROM_REQ: 'YANGMAN_FILL_NODE_FROM_REQ',
+        YANGMAN_EXECUTE_WITH_DATA: 'YANGMAN_EXECUTE_WITH_DATA',
+        YANGMAN_DESELECT_REQUESTS: 'YANGMAN_DESELECT_REQUESTS',
+        YANGMAN_REFRESH_COLLECTIONS: 'YANGMAN_REFRESH_COLLECTIONS',
+        YANGMAN_REFRESH_HISTORY: 'YANGMAN_REFRESH_HISTORY',
+        YANGMAN_SAVE_EXECUTED_REQUEST: 'YANGMAN_SAVE_EXECUTED_REQUEST',
+        YANGMAN_SELECT_THE_NEWEST_REQUEST: 'YANGMAN_SELECT_THE_NEWEST_REQUEST',
+        YANGMAN_SAVE_REQUEST_TO_COLLECTION: 'YANGMAN_SAVE_REQUEST_TO_COLLECTION',
+        YANGMAN_REFRESH_AND_EXPAND_COLLECTIONS: 'YANGMAN_REFRESH_AND_EXPAND_COLLECTIONS',
+        YANGMAN_SET_ERROR_DATA: 'YANGMAN_SET_ERROR_DATA',
+        YANGMAN_SET_ERROR_MESSAGE: 'YANGMAN_SET_ERROR_MESSAGE',
+        YANGMAN_EXECUTING_REQUEST_PROGRESS_START: 'YANGMAN_EXECUTING_REQUEST_PROGRESS_START',
+        YANGMAN_EXECUTING_REQUEST_PROGRESS_STOP: 'YANGMAN_EXECUTING_REQUEST_PROGRESS_STOP',
+        YANGMAN_GET_CODEMIRROR_DATA_RECEIVED: 'YANGMAN_GET_CODEMIRROR_DATA_RECEIVED',
+        YANGMAN_GET_CODEMIRROR_DATA_SENT: 'YANGMAN_GET_CODEMIRROR_DATA_SENT',
+        YANGMAN_SET_CODEMIRROR_DATA_RECEIVED: 'YANGMAN_SET_CODEMIRROR_DATA_RECEIVED',
+        YANGMAN_SET_CODEMIRROR_DATA_SENT: 'YANGMAN_SET_CODEMIRROR_DATA_SENT',
+        YANGMAN_ERROR_EMPTY_IDENTIFIERS: 'YANGMAN_ERROR_EMPTY_IDENTIFIERS',
+        YANGMAN_NO_MOUNT_POINT: 'YANGMAN_NO_MOUNT_POINT',
+        YANGMAN_CUST_MOUNT_POINTS: 'YANGMAN_CUST_MOUNT_POINTS',
+        YANGMAN_CANCEL_MP: 'YANGMAN_CANCEL_MP',
+        YANGMAN_MOUNT_POINT: 'YANGMAN_MOUNT_POINT',
+        SET_SCOPE_TREE_ROWS: 'SET_SCOPE_TREE_ROWS',
+        TREE_ROWS: 'tree_rows',
     };
 
 });
index 32f47294f0b1f82fbbdc96f03b691f002c56c140..c67cca7ac5ba28790f8969d9809060bccc2c60a6 100644 (file)
@@ -11,7 +11,7 @@ define([], function () {
                 processSingleRootNode: processSingleRootNode,
             },
             storageOperations = {
-                config: ['GET', 'PUT', 'DELETE'],
+                config: ['GET', 'PUT', 'POST', 'DELETE'],
                 operational: ['GET'],
                 operations: ['POST'],
             },
@@ -244,7 +244,6 @@ define([], function () {
                 });
             });
 
-            // console.info(co);
         }
 
         // TODO: add service's description
index d3af1e9e76430c2abc72f2d3ef0316abf61f8d91..33e587507abb353f40ac0e1c3c98a54fb5c380df 100644 (file)
@@ -30,12 +30,8 @@ define([], function () {
                 this.callback = callback;
             };
 
-            this.runCallback = function (args) {
-                if (this.callback) {
-                    this.callback(args);
-                } else {
-                    console.warn('no callback set for custom functionality', this.label);
-                }
+            this.runCallback = function (args){
+                (this.callback || angular.noop)(args);
             };
         }
 
index 09e668ae96996d08bd8f39b2c887648935b64989..5bf489c4c13d3e070bba854d3c71f9dcbe7facb9 100644 (file)
@@ -16,26 +16,33 @@ define([], function () {
             return key || 'DEFAULT';
         }
 
-        // TODO: add service's description
+        /**
+         * Method for storing values from scope
+         * @param variables
+         * @param scope
+         * @param key
+         */
         function storeFromScope(variables, scope, key) {
             var data = {};
             key = getKey(key);
 
             variables.forEach(function (k) {
-                if (scope.hasOwnProperty(k)) {
-                    data[k] = scope[k];
-                } else {
-                    console.warn('scope doesn\'t have variable', k);
-                }
+                data[k] = scope[k];
             });
             service.storedData[key] = data;
         }
 
-        // TODO: add service's description
+        /**
+         * Method for putting stored values to scope
+         * @param variables
+         * @param scope
+         * @param key
+         */
         function getToScope(variables, scope, key) {
             var data = {};
 
             key = getKey(key);
+
             if (service.storedData.hasOwnProperty(key)) {
                 data = service.storedData[key];
 
@@ -43,7 +50,6 @@ define([], function () {
                     if (data.hasOwnProperty(k)) {
                         scope[k] = data[k];
                     } else {
-                        console.warn('storet data doesn\'t have variable', k);
                     }
                 });
             }
index 83eea95764c4dded87d831f9323f4d68539e2ab3..75d645e0172c0e65fe2816551c1d5bbe3f0f0145 100644 (file)
@@ -128,7 +128,6 @@ define([], function () {
                                 try {
                                     valueStr = string.toString();
                                 } catch (e) {
-                                    console.warn('cannot convert value', node.value);
                                 }
                                 return valueStr;
                             };
index 2fef2b843882f28d3d9c9c939873f8a2376304a3..bd8529bf57060ce2631b80558c841af7449acf57 100644 (file)
@@ -115,7 +115,6 @@ define([], function () {
             });
 
             getActElementFilter(node);
-            // console.info('applyFilter node', node, 'node.referenceNode.filterNodes',
             // node.referenceNode.filterNodes, 'node.referenceNode.filters', node.referenceNode.filters);
         }
 
index c353ee1971a2c8c78fcb17d3edc02caf237f7caa..43837b09d2fba159bd0a063636089250e6e76601 100644 (file)
@@ -38,7 +38,7 @@ define([], function () {
         }
 
         // TODO: add function's description
-        function uses(usesNode, currentModule) {
+        function uses(usesNode, currentModule, parentNode) {
             var targetType = 'grouping';
             return function (modules) {
                 var data = findLinkedStatement(usesNode, targetType, currentModule, modules),
@@ -47,7 +47,12 @@ define([], function () {
                     changed = false;
 
                 if (node && module) {
-                    usesNode.parent.children.splice(usesNode.parent.children.indexOf(usesNode), 1); // delete uses node
+                    if (usesNode.parent.children) { // if parent is node
+                        usesNode.parent.children.splice(usesNode.parent.children.indexOf(usesNode), 1); // delete uses node
+                    }
+                    else if (usesNode.parent._roots) { // if parent is module
+                        usesNode.parent._roots.splice(usesNode.parent._roots.indexOf(usesNode), 1);
+                    }
                     for (var i = 0; i < node.children.length; i++) {
                         applyLinks(node.children[i], module, modules);
                     }
@@ -60,7 +65,7 @@ define([], function () {
         }
 
         // TODO: add function's description
-        function type(typeNode, currentModule) {
+        function type(typeNode, currentModule, parentNode) {
             var targetType = 'typedef';
 
             if (isBuildInType(typeNode.label) === false) {
@@ -71,8 +76,9 @@ define([], function () {
 
                     if (node) {
                         // delete referencing type node
-                        typeNode.parent.children.splice(typeNode.parent.children.indexOf(typeNode), 1);
-                        typeNode.parent.addChild(node);
+
+                        parentNode.children.splice(typeNode.parent.children.indexOf(typeNode), 1);
+                        parentNode.addChild(node);
                         changed = true;
                     }
 
@@ -131,14 +137,14 @@ define([], function () {
         }
 
         // TODO: add function's description
-        function applyLinks(node, module, modules) {
+        function applyLinks(node, module, modules, parentNode) {
             var changed = false;
             if (linkFunctions.hasOwnProperty(node.type)) { // applying link function to uses.node
-                changed = linkFunctions[node.type](node, module)(modules);
+                changed = linkFunctions[node.type](node, module, parentNode)(modules);
             }
 
             for (var i = 0; i < node.children.length; i++) {
-                if (applyLinks(node.children[i], module, modules)) {
+                if (applyLinks(node.children[i], module, modules, node)) {
                     i--;
                     // need to repeat current index because we are deleting uses nodes,
                     // so in case there are more uses in row, it would skip second one
index c16a5b8bb579985ce3a055d3826c497fc7fc1476..120921ebbb9f6257d1e709f660d7c0153403ad02 100644 (file)
@@ -12,7 +12,7 @@ define([], function () {
 
         // TODO: add service's description
         function isRootNode(type) {
-            return type === 'container' || type === 'list' || type === 'rpc';
+            return type === 'container' || type === 'list' || type === 'uses' || type === 'rpc';
         }
 
         // TODO: add service's description
index 8d7d217c805efcdf508298accffd0d7fad933180..af091f2ce733dfb7262685131095abea3a0b4eca 100644 (file)
@@ -137,6 +137,7 @@ define([], function () {
             node.buildActElemData = function () {
                 var list = [],
                     result;
+
                 if (node.actElemStructure) {
                     node.actElemStructure.listElemBuildRequest(RequestBuilderService, list, node.module);
                     result = list[0] ? list[0] : {};
@@ -169,9 +170,9 @@ define([], function () {
                 }
 
                 node.actElemStructure.clear();
-                for (var prop in actData) {
+                Object.keys(actData).forEach(function(prop) {
                     node.actElemStructure.fillListElement(prop, actData[prop]);
-                }
+                });
 
                 EventDispatcherService.dispatch(constants.EV_LIST_CHANGED, node.actElemStructure);
             };
@@ -195,9 +196,9 @@ define([], function () {
                     var actData = node.listData[node.actElemIndex];
 
                     node.actElemStructure.clear();
-                    for (var prop in actData) {
+                    Object.keys(actData).forEach(function(prop) {
                         node.actElemStructure.fillListElement(prop, actData[prop]);
-                    }
+                    });
                 }
 
                 EventDispatcherService.dispatch(constants.EV_LIST_CHANGED, node.actElemStructure);
@@ -224,11 +225,11 @@ define([], function () {
 
                 var buildedDataCopy = node.listData.slice().map(function (item) {
                     var newItem = {};
-                    for (var prop in item){
+                    Object.keys(item).forEach(function(prop) {
                         if (prop !== '$$hashKey'){
                             newItem[prop] = item[prop];
                         }
-                    }
+                    });
                     return newItem;
                 }).filter(function (item){
                     return Object.keys(item).length !== 0;
@@ -256,9 +257,10 @@ define([], function () {
                     node.createStructure();
                     node.listData = array.slice();
                     node.actElemIndex = node.listData.length - 1;
-                    for (var prop in node.listData[node.actElemIndex]) {
+
+                    Object.keys(node.listData[node.actElemIndex]).forEach(function(prop) {
                         node.actElemStructure.fillListElement(prop, node.listData[node.actElemIndex][prop]);
-                    }
+                    });
                 }
 
                 return (match && array.length > 0);
@@ -543,9 +545,9 @@ define([], function () {
 
                 if (match && nodesToFill.length) {
                     nodesToFill.forEach(function (child) {
-                        for (var prop in data) {
+                        Object.keys(data).forEach(function(prop) {
                             child.fill(prop, data[prop]);
-                        }
+                        });
                     });
                     node.expanded = match;
                 }
@@ -604,9 +606,9 @@ define([], function () {
 
                 if (match && nodesToFill.length) {
                     nodesToFill.forEach(function (child) {
-                        for (var prop in data) {
+                        Object.keys(data).forEach(function(prop) {
                             child.fill(prop, data[prop]);
-                        }
+                        });
                     });
                     node.expanded = match;
                 }
@@ -662,17 +664,20 @@ define([], function () {
             };
 
             node.fill = function (name, data) {
-                var filled = false,
+                var match = comparePropToElemByName(name, node.label),
                     nodesToFill = node.getChildren(null, null, constants.NODE_UI_DISPLAY);
 
-                nodesToFill.forEach(function (child) {
-                    var childFilled = child.fill(name, data);
-                    filled = filled || childFilled;
-                });
+                if (match && nodesToFill.length) {
+                    nodesToFill.forEach(function (child) {
+                        Object.keys(data).forEach(function(prop) {
+                            child.fill(prop, data[prop]);
+                        });
+                    });
+                }
 
-                node.expanded = filled;
+                node.expanded = match;
 
-                return filled;
+                return match;
             };
 
             node.clear = function () {
@@ -745,9 +750,9 @@ define([], function () {
 
                 if (match && nodesToFill.length) {
                     nodesToFill.forEach(function (child) {
-                        for (var prop in data) {
+                        Object.keys(data).forEach(function(prop) {
                             child.fill(prop, data[prop]);
-                        }
+                        });
                     });
 
                     node.expanded = match;
@@ -993,7 +998,6 @@ define([], function () {
             };
 
             node.getChildren('type').forEach(function (child) {
-                // console.info('child', child);
                 getTypesRecursive(child, types);
             });
 
index aa83b625ec487db95bfed6a415fb11bc138205e7..7a775fb22d53a3c5f9ce06fd80c02a1494649195 100644 (file)
@@ -4,6 +4,8 @@ define([], function () {
     function PathUtilsService(ArrayUtilsService){
 
         var service = {
+                clearPath: clearPath,
+                checkEmptyIdentifiers: checkEmptyIdentifiers,
                 createPathElement: createPathElement,
                 getModuleNameFromPath: getModuleNameFromPath,
                 getStorageAndNormalizedPath: getStorageAndNormalizedPath,
@@ -47,13 +49,20 @@ define([], function () {
                     return selNode;
                 }
             } else {
-                console.warn('search: cannot find element ', pathElem.name);
                 return null;
             }
         }
 
-        // TODO: add service's description
-        function translate(path, prefixConverter, importNodes, getDefaultModuleCallback) {
+        /**
+         * Translate path url into path elements array
+         * @param path
+         * @param prefixConverter
+         * @param importNodes
+         * @param getDefaultModuleCallback
+         * @param notIdentifiers
+         * @returns {Array}
+         */
+        function translate(path, prefixConverter, importNodes, getDefaultModuleCallback, notIdentifiers) {
             var pathStrElements = path.split('/').filter(function (e) {
                     return e !== '';
                 }),
@@ -72,9 +81,10 @@ define([], function () {
 
             for (index = 0; index < maxIndex; index += 1) {
                 var actElem = pathStrElements[index],
-                    lastElem = getLastElement(pathArrayElements);
+                    lastElem = getLastElement(pathArrayElements),
+                    checkIdentifier = notIdentifiers ? false : isIdentifier(actElem);
 
-                if (isIdentifier(actElem) && lastElem) {
+                if (checkIdentifier && lastElem) {
                     lastElem.addIdentifier(actElem.slice(1, -1));
                 } else {
 
@@ -97,7 +107,7 @@ define([], function () {
         function translatePathArray(pathArray) {
             var getIdentifiersValues = function (identifiers) {
                     return identifiers.map(function (i) {
-                        return i.value.replace(/\//g, '%2F');
+                        return i.value.length ? i.value.replace(/\//g, '%2F') : '{' + i.label + '}';
                     }).join('/');
                 },
                 getLastElem = function (i) {
@@ -123,7 +133,22 @@ define([], function () {
             });
         }
 
-        // TODO: add service's description
+        /**
+         * Check if in path elements array is empty identifier
+         * @param pathArray
+         * @returns {*}
+         */
+        function checkEmptyIdentifiers(pathArray){
+            return pathArray.some(function (item) {
+                return item.hasEmptyIdentifier();
+            });
+        }
+
+        /**
+         * Service for filling API url object from url string data
+         * @param pathArrayIn
+         * @param pathString
+         */
         function fillPath(pathArrayIn, pathString) {
             var pathArray = trimPath(pathString).split('/'),
                 pathPosition = 0;
@@ -132,7 +157,7 @@ define([], function () {
                 if ( pathItem.hasIdentifier() ){
                     pathItem.identifiers.forEach(function (identifier){
                         pathPosition++;
-                        identifier.value = pathArray[pathPosition];
+                        identifier.value = isIdentifier(pathArray[pathPosition]) ? '' : pathArray[pathPosition];
                     });
                 }
                 pathPosition++;
@@ -140,6 +165,20 @@ define([], function () {
 
         }
 
+        /**
+         * Service for clearing api path object
+         * @param pathArrayIn
+         */
+        function clearPath(pathArrayIn){
+            pathArrayIn.forEach(function (pathItem){
+                if ( pathItem.hasIdentifier() ){
+                    pathItem.identifiers.forEach(function (identifier){
+                        identifier.value = '';
+                    });
+                }
+            });
+        }
+
         // TODO: add service's description
         function getModuleNameFromPath(path){
             var pathArray = translate(trimPath(path));
@@ -148,8 +187,8 @@ define([], function () {
         }
 
         // TODO: add service's description
-        function searchNodeByPath(pathString, treeApis, treeData, disabledExpand) {
-            var pathArray = translate(trimPath(pathString)),
+        function searchNodeByPath(pathString, treeApis, treeData, disabledExpand, notIdentifiers) {
+            var pathArray = translate(trimPath(pathString), null, null, null, notIdentifiers),
                 module = pathArray.length > 1 ? pathArray[1].module : null,
                 selectedTreeApi = module ? treeApis.filter(function (treeApi) {
                     return treeApi.module === module;
@@ -189,7 +228,12 @@ define([], function () {
             return retObj;
         }
 
-        // TODO: add service's description
+        /**
+         * Fill path element's identifiers
+         * @param identifiers
+         * @param label
+         * @param value
+         */
         function fillIdentifiers(identifiers, label, value) {
             identifiers.some(function (i) {
                 var identifierMatch = i.label === label;
@@ -307,6 +351,12 @@ define([], function () {
                 });
             };
 
+            this.hasEmptyIdentifier = function () {
+                return this.identifiers.some(function (item) {
+                    return item.value.length === 0;
+                });
+            };
+
             this.toString = function () {
                 return (this.module ? this.module + ':' : '') + this.name + '/' + (this.hasIdentifier() ?
                                                                     this.getIdentifierValues().join('/') + '/' : '');
index 56ebe8d88c7a8a9f42cb72c63a51fbf785bfef6e..38c657f326adc3ef0e7b7bd505742ea4af2477f9 100644 (file)
@@ -24,7 +24,6 @@ define([], function () {
             this.spawnRequest = function (digest) {
                 var id = digest + (this.reqId++).toString();
                 this.runningRequests.push(id);
-                // console.debug('adding request ',id,' total running requests  = ',this.runningRequests);
                 return id;
             };
 
@@ -33,9 +32,7 @@ define([], function () {
 
                 if (index > -1) {
                     this.runningRequests.splice(index, 1);
-                    // console.debug('removing request ',id,' remaining requests = ',this.runningRequests);
                 } else {
-                    console.warn('cannot remove request', id, 'from', this.runningRequests, 'index is', index);
                 }
             };
 
@@ -45,7 +42,6 @@ define([], function () {
                     self = this;
 
                 if (processes > 0 && self.timeElapsed < timeout) {
-                    // console.debug('waitin on',processes,'processes',this.runningRequests);
                     $timeout(function () {
                         self.timeElapsed = self.timeElapsed + t;
                         self.waitFor(callback);
index 275307c5b1a07912be05648723d6ff0e8db2e002..5a243c596e121c45a99fbb5d74951832ba81bafd 100644 (file)
@@ -214,7 +214,6 @@ define([], function () {
                     try {
                         valueStr = string.toString();
                     } catch (e) {
-                        console.warn('cannot convert value', node.value);
                     }
                 }
 
index bc5c666c17bf2b5e716aef4b4676f3283b31a6c1..7cb89580e041ea4a240d249dff369e43cad2f87f 100644 (file)
@@ -8,6 +8,7 @@ define(['angular'], function (angular) {
             generateApiTreeData: generateApiTreeData,
             generateNodesToApis: generateNodesToApis,
             objectHandler: objectHandler,
+            postRequestData: postRequestData,
             prepareHeaders: prepareHeaders,
             prepareOperation: prepareOperation,
             prepareRequestData: prepareRequestData,
@@ -69,8 +70,8 @@ define(['angular'], function (angular) {
 
         // TODO: add service's description
         function switchConfigOper(apiStr, swtichTo) {
-            var c = 'config',
-                o = 'operational',
+            var c = constants.DATA_STORE_CONFIG,
+                o = constants.DATA_STORE_OPERATIONAL,
                 str = apiStr;
 
             if (apiStr.indexOf(c) === 0) {
@@ -395,13 +396,14 @@ define(['angular'], function (angular) {
         }
 
         // TODO: add service's description
+        // TODO: seems to be not used more
         function prepareRequestData(requestData, operation, reqString, subApi){
             var preparedData = requestData;
 
-            if (operation === 'GET'){
+            if (operation === constants.OPERATION_GET || operation === constants.OPERATION_DELETE){
                 preparedData = null;
             }
-            else if (operation === 'POST'){
+            else if (operation === constants.OPERATION_POST){
                 return postRequestData(requestData, reqString, subApi);
             }
 
@@ -410,7 +412,7 @@ define(['angular'], function (angular) {
 
         // TODO: add service's description
         function prepareOperation(operation){
-            return operation === 'DELETE' ? 'REMOVE' : operation;
+            return operation === constants.OPERATION_DELETE ? 'REMOVE' : operation;
         }
 
         // TODO: add service's description
index c2d1210a7b8aee9300a7768fa265301678de5f53..c1f32d6c87332a32f4bfd7852379fb7702d10212 100644 (file)
@@ -81,10 +81,8 @@ define([], function () {
         function loadStaticModule(name, callback, errorCbk) {
             var yinPath = '/yang2xml/' + name + '.yang.xml';
             $http.get(path + yinPath).success(function (data) {
-                console.warn('cannot load ' + name + 'from controller, trying loading from static storage');
                 parseModule(data, callback);
             }).error(function () {
-                console.warn('cannot load file ' + yinPath + 'from static storage');
                 errorCbk();
                 return null;
             });
@@ -156,7 +154,6 @@ define([], function () {
                 });
 
                 if (duplicates && duplicates.length > 0) {
-                    console.warn('trying to add duplicate node', node, 'to module', this._statements);
                 } else {
                     this._statements[node.type].push(node);
 
@@ -181,9 +178,7 @@ define([], function () {
                 }
 
                 if (searchResults && searchResults.length === 0) {
-                    // console.warn('no nodes with type', type, 'and name', name, 'found in', this);
                 } else if (searchResults && searchResults.length > 1) {
-                    // console.warn('multiple nodes with type', type, 'and name', name, 'found in', this);
                 } else if (searchResults && searchResults.length === 1) {
                     searchedNode = searchResults[0];
                 }
@@ -347,7 +342,6 @@ define([], function () {
                         // });
                     });
                 } else {
-                    console.warn('can\'t find target node for augmentation ', this.getPathString());
                 }
             };
 
@@ -401,7 +395,7 @@ define([], function () {
             };
 
             this.config = function (xml, parent) {
-                var type = 'config',
+                var type = constants.DATA_STORE_CONFIG,
                     name = $(xml).attr('value'),
                     nodeType = constants.NODE_ALTER;
 
@@ -540,7 +534,7 @@ define([], function () {
 
 
             this.rpc = function (xml, parent) {
-                var type = 'rpc',
+                var type = constants.NODE_RPC,
                     name = $(xml).attr('name'),
                     nodeType = constants.NODE_UI_DISPLAY,
                     node = this.createNewNode(name, type, parent, nodeType);
index 69054d9d8a68482c4deeabf388a8d85c75a599af..a25431f81beb3e222592c6e0f7802ef7f9e60eb9 100644 (file)
@@ -12,7 +12,7 @@
   <parent>
     <groupId>org.opendaylight.dlux</groupId>
     <artifactId>dlux-parent</artifactId>
-    <version>0.4.0-SNAPSHOT</version>
+    <version>0.5.0-SNAPSHOT</version>
     <relativePath>../../</relativePath>
   </parent>
 
index fd8b65bee516813d924bdb5391a93f8d1ca734fd..018eb02515db1cf8c97731c8eb8b7a95be336e6a 100644 (file)
@@ -12,7 +12,7 @@
   <parent>
     <groupId>org.opendaylight.dlux</groupId>
     <artifactId>dlux-parent</artifactId>
-    <version>0.4.0-SNAPSHOT</version>
+    <version>0.5.0-SNAPSHOT</version>
     <relativePath>../../</relativePath>
   </parent>
 
index 08e530add52c062399d63f4b5989346ce74a28b3..779cb3438e6e975fe19455fd18deccade648b694 100644 (file)
@@ -12,7 +12,7 @@
   <parent>
     <groupId>org.opendaylight.dlux</groupId>
     <artifactId>dlux-parent</artifactId>
-    <version>0.4.0-SNAPSHOT</version>
+    <version>0.5.0-SNAPSHOT</version>
     <relativePath>../../</relativePath>
   </parent>
 
index 6e38d38d267870a1265205f9bf0c2e173938bd17..51cbd93e11dce05f553e021415ca21f50dc26955 100644 (file)
@@ -12,7 +12,7 @@
   <parent>
     <groupId>org.opendaylight.dlux</groupId>
     <artifactId>dlux-parent</artifactId>
-    <version>0.4.0-SNAPSHOT</version>
+    <version>0.5.0-SNAPSHOT</version>
     <relativePath>../../</relativePath>
   </parent>
 
index 4e5aeaf899abfc88daa98bfae172b0afb8b0e42f..5276a4269efbff0e15c253866baa37e4fa0caced 100644 (file)
@@ -12,7 +12,7 @@
   <parent>
     <groupId>org.opendaylight.dlux</groupId>
     <artifactId>dlux-parent</artifactId>
-    <version>0.4.0-SNAPSHOT</version>
+    <version>0.5.0-SNAPSHOT</version>
     <relativePath>../../</relativePath>
   </parent>
 
index ae13dca45bcad6634a26cab9e77a36f9e86f53e6..3773b5e6b6f5ff1e519dd0fd432ac861385414c1 100644 (file)
@@ -21,6 +21,7 @@ var deps = [
   'app/topology/topology.module',
   'common/login/login.module',
   'app/yangui/main',
+  'app/yangman/main',
   'app/yangvisualizer/yangvisualizer.module',
   'common/sigmatopology/sigmatopology.module',
   'common/navigation/navigation.module',
@@ -41,6 +42,7 @@ var e = [
   'app.topology',
   'app.common.login',
   'app.yangui',
+  'app.yangman',
   'app.yangvisualizer',
   'app.common.sigmatopology',
   'app.common.nav',
index efcedda30283797ea549a8694a2a43b1a210af40..5c3fad8b664c9843e1e151b6cfca07e4b8772618 100644 (file)
 #wrapper {\r
     width: 100%;\r
     padding-left:250px;\r
-}\r
-\r
-#pageContent {\r
-  margin-bottom:50px;\r
+    height: calc(100% - 62px);\r
+    overflow-y: auto;\r
+    overflow-x: hidden;\r
 }\r
 \r
 #sideMenu {\r
@@ -24,7 +23,7 @@
   position: absolute;\r
   left: 250px;\r
   width: 250px;\r
-  height: 100%;\r
+  height: calc(100% - 62px);\r
   margin-left: -250px;\r
   overflow-y: auto;\r
   background: #808285;\r
     padding:0 15px;\r
     position: relative;\r
     width:100%;\r
+    height: 100%;\r
+}\r
+\r
+#page-wrapper-content > div.container-fluid,\r
+#page-wrapper-content > div.container-fluid > div.row,\r
+#pageContent{\r
+    height: 100%;\r
 }\r
 \r
 .navbar-static-side ul li {\r
diff --git a/modules/loader-resources/src/main/resources/assets/images/logo_yangman.png b/modules/loader-resources/src/main/resources/assets/images/logo_yangman.png
new file mode 100644 (file)
index 0000000..448e926
Binary files /dev/null and b/modules/loader-resources/src/main/resources/assets/images/logo_yangman.png differ
similarity index 84%
rename from modules/yangui-resources/src/main/resources/yangui/assets/js/codemirror/addon/hint/yangui-json-hint.js
rename to modules/loader-resources/src/main/resources/assets/js/codemirror/addon/hint/json-parameters-hint.js
index 50d5707d30f55c3e9c02dfabc4a3ccbed4e6a1f9..1aefeee3f3bf07ca78f6b7d385b949f63a05bd1c 100644 (file)
 
     var WORD = /[<<\w$]+/, RANGE = 500;
     CodeMirror.registerHelper("hint", "anyword", function(editor, options) {
+
         var acList = [],
             word = options && options.word || WORD,
-            cur = editor.getCursor(), 
+            cur = editor.getCursor(),
             curLine = editor.getLine(cur.line),
-            end = cur.ch, 
+            end = cur.ch,
             start = end,
             paramList = editor.data.parameterListObj.list;
-            
+
         function forEachParam(arr, f, fParam) {
-            for (var i = 0, e = arr.length; i < e; ++i){ 
+            for (var i = 0, e = arr.length; i < e; ++i){
                 f(arr[i].name, fParam);
-            };
+            }
         }
-        
-        
+
+
         function maybeAdd(possibleWord, word) {
             var pw = '<<' + possibleWord + '>>';
-            if (pw.lastIndexOf(word, 0) == 0 && !arrayContains(acList, pw)) 
+            if (pw.lastIndexOf(word, 0) == 0 && !arrayContains(acList, pw))
                 acList.push(pw);
         }
-        
+
         function arrayContains(arr, item) {
             if (!Array.prototype.indexOf) {
                 var i = arr.length;
             }
             return arr.indexOf(item) != -1;
         }
-        
-        
+
+
         options.completeSingle = false;
-        
-        while (start && word.test(curLine.charAt(start - 1))) 
+
+        while (start && word.test(curLine.charAt(start - 1)))
             --start;
-        
+
         var curWord = curLine.slice(start, end);
-        
+
         if(curWord.length > 1){
             forEachParam(paramList, maybeAdd, curWord);
         }
-        
-        
-        
+
+
+
         return {list: acList, from: CodeMirror.Pos(cur.line, start), to: CodeMirror.Pos(cur.line, end)};
     });
 });
similarity index 99%
rename from modules/yangui-resources/src/main/resources/yangui/assets/js/codemirror/lib/codemirror.js
rename to modules/loader-resources/src/main/resources/assets/js/codemirror/lib/codemirror.js
index 0c557873b33e11d4d65bc4e4c3eefff0f15469f3..4df0cff86763249f60a2694d242e92cbf49486fe 100644 (file)
     var pasted = e.clipboardData && e.clipboardData.getData("text/plain");
     if (pasted) {
       e.preventDefault();
-      runInOp(cm, function() { applyTextInput(cm, pasted, 0, null, "paste"); });
+      if (!isReadOnly(cm) && !cm.options.disableInput)
+        runInOp(cm, function () { applyTextInput(cm, pasted, 0, null, "paste"); });
       return true;
     }
   }
index 29b6af8bed9f743327db140dc777bd2683ab6722..ce4e2604ceda25b9a3272cabf07221091c5b1dad 100644 (file)
@@ -25,6 +25,8 @@
     <link rel="stylesheet" type="text/css" href="vendor/footable/css/footable.standalone.min.css" />
     <link rel="stylesheet" type="text/css" href="vendor/vis/dist/vis.min.css" />
     <link rel="stylesheet" type="text/css" href="vendor/ng-slider/dist/css/ng-slider.min.css" />
+    <link rel="stylesheet" type="text/css" href="vendor/angular-material/angular-material.css" />
+    <link rel="stylesheet" type="text/css" href="vendor/material-design-icons/iconfont/material-icons.css" />
     <link rel="stylesheet" type="text/css" href="assets/opendaylight-dlux-0.2.0.css" />
     <link rel="stylesheet" href="assets/css/sb-admin.css" />
 
@@ -36,6 +38,6 @@
   </head>
 
   <body class="skin-3">
-  <div ui-view="mainContent"></div>
+    <div ui-view="mainContent" id="main-content-container"></div>
   </body>
 </html>
index 4f32f446fd6dd6ee02f65c476b7fe51f27b8171a..a7f7199839b2999b747b9df7f0211c735fe599f6 100644 (file)
@@ -1,5 +1,10 @@
 require.config({
   baseUrl : 'src',
+  packages: [{
+    name: 'codemirror',
+    location: '../assets/js/codemirror',
+    main: 'lib/codemirror',
+  }],
   paths : {
     'angular' : '../vendor/angular/angular',
     'ui-bootstrap' : '../vendor/angular-bootstrap/ui-bootstrap-tpls.min',
@@ -27,6 +32,14 @@ require.config({
     'ZeroClipboard' : '../vendor/zeroclipboard/dist/ZeroClipboard',
     'ngClip' : '../vendor/ng-clip/src/ngClip',
     'angular-translate-loader-partial' : '../vendor/angular-translate-loader-partial/angular-translate-loader-partial',
+    'ngAnimate': '../vendor/angular-animate/angular-animate.min',
+    'ngAria': '../vendor/angular-aria/angular-aria.min',
+    'ngMaterial': '../vendor/angular-material/angular-material.min',
+    'ngMessages': '../vendor/angular-messages/angular-messages.min',
+    'codeMirror-showHint' : '../assets/js/codemirror/addon/hint/show-hint',
+    'codeMirror-jsonParametersHint' : '../assets/js/codemirror/addon/hint/json-parameters-hint',
+    'codeMirror-javascriptMode' : '../assets/js/codemirror/mode/javascript/javascript',
+    'codeMirror-matchBrackets' : '../assets/js/codemirror/addon/edit/matchbrackets',
   },
   map: {
     '*': {
@@ -66,7 +79,16 @@ require.config({
     'ngSlider' : ['angular'],
     'ZeroClipboard': ['angular'],
     'ngClip' : ['angular','ZeroClipboard'],
-    'angular-translate-loader-partial': ['angular-translate']
+    'angular-translate-loader-partial': ['angular-translate'],
+    'ngAnimate': ['angular'],
+    'ngAria': ['angular'],
+    'ngMaterial': {
+      deps: ['ngAnimate', 'ngAria']
+    },
+    'codeMirros_showHint': ['codemirror'],
+    'codeMirros_javascriptHint': ['codemirror'],
+    'codeMirror_javascriptMode': ['codemirror'],
+    'codeMirror_matchBrackets': ['codemirror'],
   },
 
   deps : ['app/app.module']
index 441981729c902378fc44d8abba69d11c4a5760f4..6ccfd823fac4fb6a3f0e2c1b22b0a438a013ae26 100644 (file)
@@ -12,7 +12,7 @@
   <parent>
     <groupId>org.opendaylight.dlux</groupId>
     <artifactId>dlux-parent</artifactId>
-    <version>0.4.0-SNAPSHOT</version>
+    <version>0.5.0-SNAPSHOT</version>
     <relativePath>../../</relativePath>
   </parent>
 
index 36db2595013505df20b15a8c373e55c89cd69fe1..277e3826eb19a0099ce02efec7a684a6ede2e51b 100644 (file)
@@ -12,7 +12,7 @@
   <parent>
     <groupId>org.opendaylight.dlux</groupId>
     <artifactId>dlux-parent</artifactId>
-    <version>0.4.0-SNAPSHOT</version>
+    <version>0.5.0-SNAPSHOT</version>
     <relativePath>../../</relativePath>
   </parent>
 
index faac77564a8983e039bc4f2d664d7db0c8e9af69..f2148f9779a0ee8442374ac9229602ffbdff68e9 100644 (file)
@@ -6,6 +6,10 @@
 * and is available at http://www.eclipse.org/legal/epl-v10.html
 */
 
+.nodes-module{
+  padding-top: 20px;
+}
+
 .indexGrid {
   position: relative;
   top: 20px;
@@ -86,13 +90,6 @@ svg {
   background-image: radial-gradient(circle, #eee, #ccc);
 }
 
-
-
-.main {
-  position: relative;
-  top: 20px;
-}
-
 .footable {
   a {
     color: #428bca !important;
index b376139154cf40e44d5922c467811d7af2580d08..2da88e8e882e9ceacb128180691895d04fc60a73 100644 (file)
@@ -5,4 +5,4 @@
 * terms of the Eclipse Public License v1.0 which accompanies this distribution,
 * and is available at http://www.eclipse.org/legal/epl-v10.html
 -->
-<div class="main" ui-view></div>
+<div class="main nodes-module" ui-view></div>
index f2a17e9e744758d2f52471d282ccb82a6b2af3d2..726e4f580943595afb2b09f55da27d7e251fb136 100644 (file)
@@ -12,7 +12,7 @@
   <parent>
     <groupId>org.opendaylight.dlux</groupId>
     <artifactId>dlux-parent</artifactId>
-    <version>0.4.0-SNAPSHOT</version>
+    <version>0.5.0-SNAPSHOT</version>
     <relativePath>../</relativePath>
   </parent>
 
@@ -33,6 +33,7 @@
     <module>common-login-resources</module>
     <module>common-general-resources</module>
     <module>yangui-resources</module>
+    <module>yangman-resources</module>
     <module>yangvisualizer-resources</module>
     <module>network-resources</module>
     <module>flow-resources</module>
index acd57c9f2dba21cb405b3d1657ef8166c4756a51..09fa298a496fac0e3793cd35a7640d78adb4655d 100644 (file)
@@ -12,7 +12,7 @@
   <parent>
     <groupId>org.opendaylight.dlux</groupId>
     <artifactId>dlux-parent</artifactId>
-    <version>0.4.0-SNAPSHOT</version>
+    <version>0.5.0-SNAPSHOT</version>
     <relativePath>../../</relativePath>
   </parent>
 
diff --git a/modules/yangman-resources/pom.xml b/modules/yangman-resources/pom.xml
new file mode 100644 (file)
index 0000000..a18eb5a
--- /dev/null
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ Copyright (c) 2014 Inocybe Technologies, and others. All rights reserved.
+
+ This program and the accompanying materials are made available under the
+ terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ and is available at http://www.eclipse.org/legal/epl-v10.html
+-->
+<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.opendaylight.dlux</groupId>
+    <artifactId>dlux-parent</artifactId>
+    <version>0.5.0-SNAPSHOT</version>
+    <relativePath>../../</relativePath>
+  </parent>
+
+  <artifactId>dlux.yangman.resources</artifactId>
+  <name>${project.artifactId}</name>
+  <description>Yangman Module Resources</description>
+  <version>${yangman.resources.version}</version>
+  <packaging>jar</packaging>
+
+</project>
diff --git a/modules/yangman-resources/src/main/resources/yangman/assets/data/locale-en_US.json b/modules/yangman-resources/src/main/resources/yangman/assets/data/locale-en_US.json
new file mode 100644 (file)
index 0000000..7e697fb
--- /dev/null
@@ -0,0 +1,101 @@
+{
+  "YANGMAN_ADD_LIST_ITEM": "Add list item",
+  "YANGMAN_AUGMENTATIONS": "Augmentations",
+  "YANGMAN_CANCEL": "Cancel",
+  "YANGMAN_CLOSE": "Close",
+  "YANGMAN_CLEAR_SEARCH": "Clear filter",
+  "YANGMAN_COLLECTION_CHANGE_NAME": "Edit collection name",
+  "YANGMAN_COLLECTION_DELETE": "Delete collection",
+  "YANGMAN_COLLECTION_DOWNLOAD": "Download collection",
+  "YANGMAN_COLLECTION_DUPLICATE": "Duplicate collection",
+  "YANGMAN_COLLECTION_EDIT": "Edit collection name",
+  "YANGMAN_COLLECTION_NAME": "Collection name",
+  "YANGMAN_COLLECTION_NAME_REQUIRED": "Collection name is required",
+  "YANGMAN_COLLECTION_NEW_COL_": "New collection ",
+  "YANGMAN_COLLECTION_NEW_NAME": "New collection name",
+  "YANGMAN_COLLECTION_REQUEST": "request",
+  "YANGMAN_COLLECTION_REQUESTS": "requests",
+  "YANGMAN_COLLECTION_WILL_BE_CREATED": " will be created",
+  "YANGMAN_CREATING_COLLECTION": "Select collection or type a new name",
+  "YANGMAN_DELETE_COL_CONFIRM_TEXT": "Selected collection will be deleted forever.",
+  "YANGMAN_DELETE_COL_CONFIRM_TITLE": "Do you want to delete collection",
+  "YANGMAN_DELETE_REQ_CONFIRM_TEXT": "Selected requests will be deleted forever.",
+  "YANGMAN_DELETE_REQ_CONFIRM_TITLE": "Do you want to delete request?",
+  "YANGMAN_EXPLAIN": "Explain",
+  "YANGMAN_FORM": "FORM",
+  "YANGMAN_IMPORT_COLLECTION": "Import collection",
+  "YANGMAN_JSON": "JSON",
+  "YANGMAN_LOADED_MODULES": "Modules were loaded.",
+  "YANGMAN_LOADED_MODULES_ERROR": "Error in loading modules.",
+  "YANGMAN_MATCHING": "Matching",
+  "YANGMAN_MODULES": "Modules",
+  "YANGMAN_NO_COLLECTIONS": "Type new collection name.",
+  "YANGMAN_OK": "OK",
+  "YANGMAN_PARAM_DONT_REPLACE" : "undefined - won't be replaced",
+  "YANGMAN_REQ_DELETE": "Delete request",
+  "YANGMAN_REQ_DUPLICATE": "Duplicate request",
+  "YANGMAN_REQ_SHOW_FORM": "Show form",
+  "YANGMAN_REQ_RUN": "Run request",
+  "YANGMAN_REQ_SHOW_JSON_DATA": "Show json data",
+  "YANGMAN_REQ_URL": "Request URL",
+  "YANGMAN_REQS_DELETE": "Delete selected",
+  "YANGMAN_REQS_DUPLICATE": "Duplicating request",
+  "YANGMAN_REQS_SAVE_TO_COL": "Save to collection",
+  "YANGMAN_SAVE": "SAVE",
+  "YANGMAN_SEL_METHOD": "Select method",
+  "YANGMAN_SEND": "SEND",
+  "YANGMAN_SHOW_LIST_ITEM": "Show all list items",
+  "YANGMAN_SORT_ASC": "ascending",
+  "YANGMAN_SORT_DESC": "descending",
+  "YANGMAN_STATUS": "Status",
+  "YANGMAN_TIME": "Time",
+  "YANGMAN_HISTORY": "History",
+  "YANGMAN_COLLECTIONS": "Collections",
+  "YANGMAN_PARAMETERS_ADMINISTRATION": "Parameters administration",
+  "YANGMAN_PARAMETERS": "Parameters",
+  "YANGMAN_RECEIVED_DATA": "Received data",
+  "YANGMAN_SENT_DATA": "Sent data",
+  "YANGMAN_PARAM_KEY": "Key",
+  "YANGMAN_PARAM_VALUE": "Value",
+  "YANGMAN_REMOVE_PARAM": "Remove param",
+  "YANGMAN_SEARCH": "Search",
+  "YANGMAN_SORT_BY": "Sort by",
+  "YANGMAN_PARAMS_KEY": "key",
+  "YANGMAN_PARAMS_VALUE": "value",
+  "YANGMAN_PARAM_KEY_REQUIRED": "Required value",
+  "YANGMAN_PARAM_EXISTING_KEY": "Duplicate value",
+  "YANGMAN_SORTING": "Sorting",
+  "YANGMAN_CUST_MOUNT_POINTS": "Display mount points",
+  "YANGMAN_CANCEL_MP": "Back from mountpoint",
+  "YANGMAN_PLUGINS_MENU": "Plugins menu",
+  "YANGMAN_PARAMS_IMPORT_EXPORT": "Import and export parameters",
+  "YANGMAN_IMPORT_PARAMS": "Import all parameters",
+  "YANGMAN_EXPORT_PARAMETERS": "Export all parameters",
+  "YANGMAN_NO_MOUNT_POINT": "No mount points to display",
+  "YANGMAN_MOUNT_POINT": "Mount point",
+  "YANGMAN_YANG_MENU": "Yang menu",
+  "YANGMAN_DELETE_HISTORY_CONFIRM_TITLE": "Do you want to delete all history requests?",
+  "YANGMAN_DELETE_HISTORY_CONFIRM_TEXT": "All history requests will be Deleted.",
+  "YANGMAN_DELETE_HISTORY": "Delete all history requests",
+  "YANGMAN_DELETE_COLLECTIONS": "Delete all collections",
+  "YANGMAN_DELETE_COLLECTION_CONFIRM_TITLE": "Do you want to delete all collections?",
+  "YANGMAN_DELETE_COLLECTION_CONFIRM_TEXT": "All collections will be deleted.",
+  "YANGMAN_DELETE_OPTIONS": "Delete options",
+  "YANGMAN_SELECT_OPTIONS": "Select options",
+  "YANGMAN_SELECT_ALL": "Select All",
+  "YANGMAN_DESELECT_ALL": "Deselect All",
+  "YANGMAN_IS_AUGMENT": "Augments",
+  "YANGMAN_LOADING_MODULES": "Loading application modules...",
+  "YANGMAN_EXECUTING_REQUEST": "Request is beeing executed...",
+  "YANGMAN_CM_ENLARGE_FONT_SIZE": "Enlarge json font size (Alt +)",
+  "YANGMAN_CM_REDUCE_FONT_SIZE": "Reduce json font size (Alt -)",
+  "YANGMAN_INPUT_REQUIRED": "Required",
+  "YANGMAN_ERROR_EMPTY_IDENTIFIERS": "Identifiers in path are required. Please fill empty identifiers for successful request execution.",
+  "YANGMAN_SORT_COLLECTIONS_DESC": "Sort collections descending",
+  "YANGMAN_SORT_COLLECTIONS_ASC": "Sort collections ascending",
+  "YANGMAN_LIST_DELETE_ITEM": "Delete list item",
+  "YANGMAN_LIST_INDEX_DUPLICATE": "Duplicated index",
+  "YANGMAN_LIST_PREV_ITEM": "show previous item",
+  "YANGMAN_LIST_NEXT_ITEM": "show next item",
+  "YANGMAN_SHOW_HIDE_CON": "show / hide container"
+}
diff --git a/modules/yangman-resources/src/main/resources/yangman/assets/images/icon-augment.svg b/modules/yangman-resources/src/main/resources/yangman/assets/images/icon-augment.svg
new file mode 100644 (file)
index 0000000..3626672
--- /dev/null
@@ -0,0 +1,44 @@
+<?xml version="1.0" encoding="iso-8859-1"?>
+<!-- Generator: Adobe Illustrator 16.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0)  -->
+<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
+<svg version="1.1" id="Capa_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
+        width="897.673px" height="897.673px" viewBox="0 0 897.673 897.673" style="enable-background:new 0 0 897.673 897.673;"
+        xml:space="preserve">
+<g>
+       <path d="M859.877,855.354L606.396,23.221C602.195,9.427,589.469,0,575.049,0H448.836H322.625c-14.42,0-27.146,9.426-31.347,23.221
+               L37.795,855.354c-6.413,21.055,9.338,42.318,31.347,42.318h181.071c15.246,0,28.479-10.515,31.922-25.367l38.312-165.216h128.39
+               h128.39l38.312,165.216c3.443,14.853,16.676,25.367,31.922,25.367h181.071C850.539,897.673,866.291,876.409,859.877,855.354z
+                M448.836,523.413h-85.578l15.191-62.147c22.096-85.624,44.192-194.726,66.29-284.493h4.097h4.097
+               c22.097,89.767,44.193,198.869,66.289,284.493l15.191,62.147H448.836z"/>
+</g>
+<g>
+</g>
+<g>
+</g>
+<g>
+</g>
+<g>
+</g>
+<g>
+</g>
+<g>
+</g>
+<g>
+</g>
+<g>
+</g>
+<g>
+</g>
+<g>
+</g>
+<g>
+</g>
+<g>
+</g>
+<g>
+</g>
+<g>
+</g>
+<g>
+</g>
+</svg>
diff --git a/modules/yangman-resources/src/main/resources/yangman/controllers/edit-collection-dialog.controller.js b/modules/yangman-resources/src/main/resources/yangman/controllers/edit-collection-dialog.controller.js
new file mode 100644 (file)
index 0000000..e449c90
--- /dev/null
@@ -0,0 +1,39 @@
+define([], function () {
+    'use strict';
+
+    angular.module('app.yangman').controller('EditCollectionDialogCtrl', EditCollectionDialogCtrl);
+
+    EditCollectionDialogCtrl.$inject = ['$mdDialog', 'collection', 'allCollections', 'duplicate'];
+
+    function EditCollectionDialogCtrl($mdDialog, collection, allCollections, duplicate) {
+        var vm = this;
+
+        vm.collection = collection;
+        vm.existingNames = [];
+        vm.duplicate = duplicate;
+        vm.collectionName = duplicate ? '' : vm.collection.name;
+
+        vm.cancel = cancel;
+        vm.save = save;
+
+        init();
+
+        function init(){
+            vm.existingNames = allCollections.map(function (item){
+                return item.name;
+            });
+        }
+
+        function cancel() {
+            $mdDialog.cancel();
+        }
+
+        function save() {
+            $mdDialog.hide([vm.collection.name, vm.collectionName]);
+        }
+
+    }
+
+    return EditCollectionDialogCtrl;
+
+});
diff --git a/modules/yangman-resources/src/main/resources/yangman/controllers/form/ym-augmentation-modal.controller.js b/modules/yangman-resources/src/main/resources/yangman/controllers/form/ym-augmentation-modal.controller.js
new file mode 100644 (file)
index 0000000..914b12e
--- /dev/null
@@ -0,0 +1,19 @@
+define([], function () {
+    'use strict';
+
+    angular.module('app.yangman').controller('YMAugmentationModalCtrl', YMAugmentationModalCtrl);
+
+    YMAugmentationModalCtrl.$inject = ['$scope'];
+
+    function YMAugmentationModalCtrl($scope){
+        $scope.init = init;
+
+        /**
+         * Initialization
+         * @param node
+         */
+        function init(node){
+            $scope.node = node;
+        }
+    }
+});
diff --git a/modules/yangman-resources/src/main/resources/yangman/controllers/form/ym-case.controller.js b/modules/yangman-resources/src/main/resources/yangman/controllers/form/ym-case.controller.js
new file mode 100644 (file)
index 0000000..0427c9e
--- /dev/null
@@ -0,0 +1,16 @@
+define([], function () {
+    'use strict';
+
+    angular.module('app.yangman').controller('YMCaseCtrl', YMCaseCtrl);
+
+    YMCaseCtrl.$inject = ['$scope'];
+
+    function YMCaseCtrl($scope){
+        var yangCase = this;
+
+        yangCase.empty = ($scope.case.children.length === 0 ||
+                        ($scope.case.children.length === 1 && $scope.case.children[0].children.length === 0));
+
+    }
+});
+
diff --git a/modules/yangman-resources/src/main/resources/yangman/controllers/form/ym-choice.controller.js b/modules/yangman-resources/src/main/resources/yangman/controllers/form/ym-choice.controller.js
new file mode 100644 (file)
index 0000000..52001b0
--- /dev/null
@@ -0,0 +1,40 @@
+define([], function () {
+    'use strict';
+
+    angular.module('app.yangman').controller('YMChoiceCtrl', YMChoiceCtrl);
+
+    YMChoiceCtrl.$inject = ['$scope', 'constants'];
+
+    function YMChoiceCtrl($scope, constants){
+        var yangChoice = this;
+
+        $scope.constants = constants;
+
+        // methods
+        yangChoice.isActionMenu = isActionMenu;
+        $scope.caseShowing = caseShowing;
+        yangChoice.toggleExpanded = toggleExpanded;
+
+        /**
+         * Show hide node
+         */
+        function toggleExpanded() {
+            $scope.node.expanded = !$scope.node.expanded;
+        }
+
+        // TODO :: do method description
+        function caseShowing(node) {
+            return !node.augmentationId ? true :
+                                    $scope.augmentations.getAugmentation(node.parent, node.augmentationId).expanded;
+        }
+
+        /**
+         * Show hide action menu
+         * @returns {boolean|*}
+         */
+        function isActionMenu() {
+            return $scope.node.augmentionGroups && $scope.node.augmentionGroups.length;
+        }
+    }
+});
+
diff --git a/modules/yangman-resources/src/main/resources/yangman/controllers/form/ym-container.controller.js b/modules/yangman-resources/src/main/resources/yangman/controllers/form/ym-container.controller.js
new file mode 100644 (file)
index 0000000..94ddc12
--- /dev/null
@@ -0,0 +1,31 @@
+define([], function () {
+    'use strict';
+
+    angular.module('app.yangman').controller('YMContainerCtrl', YMContainerCtrl);
+
+    YMContainerCtrl.$inject = ['$scope'];
+
+    function YMContainerCtrl($scope){
+        var yangContainer = this;
+
+        // methods
+        yangContainer.isActionMenu = isActionMenu;
+        yangContainer.toggleExpanded = toggleExpanded;
+
+        /**
+         * Show hide node
+         */
+        function toggleExpanded() {
+            $scope.node.expanded = !$scope.node.expanded;
+        }
+
+        /**
+         * Show hide action menu
+         * @returns {boolean|*}
+         */
+        function isActionMenu() {
+            return $scope.node.augmentionGroups && $scope.node.augmentionGroups.length;
+        }
+    }
+});
+
diff --git a/modules/yangman-resources/src/main/resources/yangman/controllers/form/ym-input.controller.js b/modules/yangman-resources/src/main/resources/yangman/controllers/form/ym-input.controller.js
new file mode 100644 (file)
index 0000000..726b9e9
--- /dev/null
@@ -0,0 +1,31 @@
+define([], function () {
+    'use strict';
+
+    angular.module('app.yangman').controller('YMInputCtrl', YMInputCtrl);
+
+    YMInputCtrl.$inject = ['$scope'];
+
+    function YMInputCtrl($scope){
+        var yangInput = this;
+
+        // methods
+        yangInput.isActionMenu = isActionMenu;
+        yangInput.toggleExpanded = toggleExpanded;
+
+        /**
+         * Show hide node
+         */
+        function toggleExpanded() {
+            $scope.node.expanded = !$scope.node.expanded;
+        }
+
+        /**
+         * Show hide action menu
+         * @returns {boolean|*}
+         */
+        function isActionMenu() {
+            return $scope.node.augmentionGroups && $scope.node.augmentionGroups.length;
+        }
+    }
+});
+
diff --git a/modules/yangman-resources/src/main/resources/yangman/controllers/form/ym-leaf-list.controller.js b/modules/yangman-resources/src/main/resources/yangman/controllers/form/ym-leaf-list.controller.js
new file mode 100644 (file)
index 0000000..190287b
--- /dev/null
@@ -0,0 +1,50 @@
+define([], function () {
+    'use strict';
+
+    angular.module('app.yangman').controller('YMLeafListCtrl', YMLeafListCtrl);
+
+    YMLeafListCtrl.$inject = ['$scope'];
+
+    function YMLeafListCtrl($scope){
+        var yangLeafList = this;
+
+        // methods
+        yangLeafList.addListElem = addListElem;
+        yangLeafList.changed = changed;
+        yangLeafList.isActionMenu = isActionMenu;
+        yangLeafList.removeListElem = removeListElem;
+        yangLeafList.toggleExpanded = toggleExpanded;
+
+
+        // TODO :: do method description
+        function addListElem() {
+            $scope.node.addListElem();
+        }
+
+        // TODO :: do method description
+        function removeListElem(elem){
+            $scope.node.removeListElem(elem);
+        }
+
+        // TODO :: do method description
+        function changed() {
+            //$scope.preview();
+            $scope.buildRootRequest();
+        }
+
+        // TODO :: do method description
+        function toggleExpanded() {
+            $scope.node.expanded = !$scope.node.expanded;
+        }
+
+
+        /**
+         * Show hide action menu
+         * @returns {boolean|*}
+         */
+        function isActionMenu() {
+            return true;
+        }
+    }
+});
+
diff --git a/modules/yangman-resources/src/main/resources/yangman/controllers/form/ym-leaf.controller.js b/modules/yangman-resources/src/main/resources/yangman/controllers/form/ym-leaf.controller.js
new file mode 100644 (file)
index 0000000..934e357
--- /dev/null
@@ -0,0 +1,68 @@
+define([], function () {
+    'use strict';
+
+    angular.module('app.yangman').controller('YMLeafCtrl', YMLeafCtrl);
+
+    YMLeafCtrl.$inject = ['$scope'];
+
+    function YMLeafCtrl($scope){
+        var types = [
+                'binary',
+                'bits',
+                'boolean',
+                'decimal64',
+                'enumeration',
+                'empty',
+                'identityref',
+                'instance-identifier',
+                'int16',
+                'int32',
+                'int64',
+                'int8',
+                'leafref',
+                'string',
+                'uint16',
+                'uint32',
+                'uint64',
+                'uint8',
+                'union',
+            ],
+            yangLeaf = this;
+
+        yangLeaf.infoBox = false;
+        yangLeaf.infoBoxSection = '';
+
+        // methods
+        yangLeaf.displayValue = displayValue;
+        yangLeaf.getLeafCentering = getLeafCentering;
+        yangLeaf.getLeafType = getLeafType;
+        yangLeaf.isActionMenu = isActionMenu;
+
+
+        function getLeafCentering(){
+            return ['union', 'bits', 'empty'].indexOf(getLeafType()) > -1 ? 'start' : 'center';
+        }
+
+        /**
+         * Get leaf type
+         * @returns {*}
+         */
+        function getLeafType(){
+            var label = $scope.node.getChildren('type')[0].label;
+            return types.indexOf(label) !== -1 ? label : 'default';
+        }
+
+        function displayValue() {
+            return $scope.node.typeChild.label !== 'empty';
+        }
+
+        /**
+         * Show hide action menu
+         * @returns {boolean|*}
+         */
+        function isActionMenu() {
+            return false;
+        }
+    }
+});
+
diff --git a/modules/yangman-resources/src/main/resources/yangman/controllers/form/ym-list.controller.js b/modules/yangman-resources/src/main/resources/yangman/controllers/form/ym-list.controller.js
new file mode 100644 (file)
index 0000000..0190a94
--- /dev/null
@@ -0,0 +1,199 @@
+define([], function () {
+    'use strict';
+
+    angular.module('app.yangman').controller('YMListCtrl', YMListCtrl);
+
+    YMListCtrl.$inject = ['$scope', 'ListFilteringService', 'NodeWrapperService', 'constants'];
+
+    function YMListCtrl($scope, ListFilteringService, NodeWrapperService, constants){
+        var yangList = this;
+
+        $scope.actElement = null;
+        $scope.showListFilter = false;
+        $scope.filterListHover = 0;
+        yangList.constants = constants;
+        yangList.currentDisplayIndex = 1;
+        yangList.displayOffsets = [-1, 0, 1];
+
+        // methods
+        $scope.activeFilter = activeFilter;
+        $scope.applyFilter = applyFilter;
+        $scope.clearFilterData = clearFilterData;
+        $scope.createNewFilter = createNewFilter;
+        $scope.getFilterData = getFilterData;
+        $scope.showListFilterWin = showListFilterWin;
+        $scope.showModalWin = showModalWin;
+        $scope.switchFilter = switchFilter;
+
+        yangList.addListElem = addListElem;
+        yangList.getListName = getListName;
+        yangList.init = init;
+        yangList.isActionMenu = isActionMenu;
+        yangList.removeListElem = removeListElem;
+        yangList.shiftDisplayNext = shiftDisplayNext;
+        yangList.shiftDisplayPrev = shiftDisplayPrev;
+        yangList.showNextButton = showNextButton;
+        yangList.showPrevButton = showPrevButton;
+        yangList.toggleExpanded = toggleExpanded;
+
+        // WATCHERS
+        $scope.$on(constants.EV_REFRESH_LIST_INDEX, function () {
+            yangList.currentDisplayIndex = 1;
+        });
+
+        $scope.$on(constants.YANGMAN_DISABLE_ADDING_LIST_ELEMENT, function() {
+            yangList.init();
+        });
+
+        /**
+         * Disable adding more then one element
+         */
+        function init() {
+            yangList.disableAddingListElement = $scope.checkAddingListElement($scope.node);
+
+            if(yangList.disableAddingListElement &&
+                !$scope.node.listData.length &&
+                $scope.selectedDatastore.label === constants.DATA_STORE_CONFIG) {
+
+                yangList.addListElem();
+            }
+        }
+
+        /**
+         * Add element into list
+         */
+        function addListElem() {
+            $scope.showListFilter = false;
+            $scope.showModal = false;
+            ListFilteringService.removeEmptyFilters($scope.node);
+            $scope.node.addListElem();
+        }
+
+        // TODO :: do method description
+        function removeListElem(elemIndex, fromFilter) {
+            $scope.node.removeListElem(elemIndex, fromFilter);
+            // $scope.preview();
+            yangList.currentDisplayIndex =
+                Math.max(Math.min(yangList.currentDisplayIndex, $scope.node.listData.length - 2), 1);
+            if ($scope.node.listData.length === 0) {
+                $scope.$broadcast('hideInfoBox');
+            }
+        }
+
+        // TODO :: do method description
+        function toggleExpanded() {
+            $scope.node.expanded = !$scope.node.expanded;
+        }
+
+        // TODO :: do method description
+        function shiftDisplayNext(typeListData) {
+            yangList.currentDisplayIndex = Math.min(yangList.currentDisplayIndex + 3, $scope.node[typeListData].length - 2);
+        }
+
+        // TODO :: do method description
+        function shiftDisplayPrev() {
+            yangList.currentDisplayIndex = Math.max(yangList.currentDisplayIndex - 3, 1);
+        }
+
+        // TODO :: do method description
+        function showPrevButton() {
+            return yangList.currentDisplayIndex > 1;
+        }
+
+        // TODO :: do method description
+        function showNextButton(typeListData) {
+            // node is selected after view is loaded
+            return $scope.node[typeListData] && yangList.currentDisplayIndex < $scope.node[typeListData].length - 2;
+        }
+
+        // TODO :: do method description
+        function showModalWin() {
+            $scope.showModal = !$scope.showModal;
+            if ($scope.showListFilter){
+                $scope.showListFilter = !$scope.showListFilter;
+            }
+        }
+
+        // TODO :: do method description
+        function showListFilterWin() {
+            $scope.showListFilter = !$scope.showListFilter;
+            if ($scope.showModal){
+                $scope.showModal = !$scope.showModal;
+            }
+            ListFilteringService.showListFilterWin($scope.filterRootNode,$scope.node);
+        }
+
+        // TODO :: do method description
+        function getFilterData() {
+            ListFilteringService.getFilterData($scope.node);
+        }
+
+        // TODO :: do method description
+        function switchFilter(showedFilter) {
+            ListFilteringService.switchFilter($scope.node, showedFilter);
+        }
+
+        // TODO :: do method description
+        function createNewFilter() {
+            ListFilteringService.createNewFilter($scope.node);
+        }
+
+        // TODO :: do method description
+        function applyFilter() {
+            ListFilteringService.applyFilter($scope.node);
+            $scope.showListFilter = !$scope.showListFilter;
+            yangList.currentDisplayIndex = 1;
+            if ($scope.node.filteredListData.length){
+                $scope.node.doubleKeyIndexes =
+                    NodeWrapperService.checkKeyDuplicity($scope.node.filteredListData, $scope.node.refKey);
+            } else {
+                $scope.node.doubleKeyIndexes =
+                    NodeWrapperService.checkKeyDuplicity($scope.node.listData, $scope.node.refKey);
+            }
+        }
+
+        // TODO :: do method description
+        function clearFilterData(changeAct, filterForClear, removeFilters) {
+            ListFilteringService.clearFilterData($scope.node, changeAct, filterForClear, removeFilters);
+            if (changeAct){
+                $scope.showListFilter = !$scope.showListFilter;
+            }
+            $scope.node.doubleKeyIndexes =
+                NodeWrapperService.checkKeyDuplicity($scope.node.listData, $scope.node.refKey);
+        }
+
+        // TODO :: do method description
+        function activeFilter(filter) {
+            if (filter.active === 1){
+                filter.active = 2;
+            } else {
+                filter.active = 1;
+            }
+        }
+
+        // TODO :: do method description
+        function getListName(offset, config) {
+            var createdListItemName = $scope.node.createListName(yangList.currentDisplayIndex + offset);
+
+            if ( createdListItemName.length > 33 ) {
+                return {
+                    name: createdListItemName.substring(0, 30) + '...',
+                    tooltip: createdListItemName,
+                };
+            } else {
+                return {
+                    name: config ? createdListItemName || '[' + (yangList.currentDisplayIndex + offset) + ']' : createdListItemName,
+                    tooltip: '',
+                };
+            }
+        }
+
+        /**
+         * Show hide action menu
+         * @returns {boolean|*}
+         */
+        function isActionMenu() {
+            return true;
+        }
+    }
+});
diff --git a/modules/yangman-resources/src/main/resources/yangman/controllers/form/ym-output.controller.js b/modules/yangman-resources/src/main/resources/yangman/controllers/form/ym-output.controller.js
new file mode 100644 (file)
index 0000000..6555782
--- /dev/null
@@ -0,0 +1,33 @@
+define([], function () {
+    'use strict';
+
+    angular.module('app.yangman').controller('YMOutputCtrl', YMOutputCtrl);
+
+    YMOutputCtrl.$inject = ['$scope'];
+
+    function YMOutputCtrl($scope){
+        var yangOutput = this;
+        yangOutput.notEditable = true;
+
+        // methods
+        yangOutput.isActionMenu = isActionMenu;
+        yangOutput.toggleExpanded = toggleExpanded;
+
+        /**
+         * Show hide node
+         */
+        function toggleExpanded() {
+            $scope.node.expanded = !$scope.node.expanded;
+        }
+
+        /**
+         * Show hide action menu
+         * @returns {boolean|*}
+         */
+        function isActionMenu() {
+            return $scope.node.augmentionGroups && $scope.node.augmentionGroups.length;
+        }
+    }
+});
+
+
diff --git a/modules/yangman-resources/src/main/resources/yangman/controllers/form/ym-rpc.controller.js b/modules/yangman-resources/src/main/resources/yangman/controllers/form/ym-rpc.controller.js
new file mode 100644 (file)
index 0000000..b77e751
--- /dev/null
@@ -0,0 +1,32 @@
+define([], function () {
+    'use strict';
+
+    angular.module('app.yangman').controller('YMRpcCtrl', YMRpcCtrl);
+
+    YMRpcCtrl.$inject = ['$scope'];
+
+    function YMRpcCtrl($scope){
+        var yangRpc = this;
+
+        // methods
+        yangRpc.toggleExpanded = toggleExpanded;
+        yangRpc.isActionMenu = isActionMenu;
+
+        /**
+         * Show hide node
+         */
+        function toggleExpanded() {
+            $scope.node.expanded = !$scope.node.expanded;
+        }
+
+        /**
+         * Show hide action menu
+         * @returns {boolean|*}
+         */
+        function isActionMenu() {
+            return false;
+        }
+
+    }
+});
+
diff --git a/modules/yangman-resources/src/main/resources/yangman/controllers/form/ym-type-bit.controller.js b/modules/yangman-resources/src/main/resources/yangman/controllers/form/ym-type-bit.controller.js
new file mode 100644 (file)
index 0000000..6b05d0a
--- /dev/null
@@ -0,0 +1,25 @@
+define([], function () {
+    'use strict';
+
+    angular.module('app.yangman').controller('YMTypeBitCtrl', YMTypeBitCtrl);
+
+    YMTypeBitCtrl.$inject = ['$scope'];
+
+    function YMTypeBitCtrl($scope){
+        var yangTypeBit = this;
+
+        // methods
+        yangTypeBit.valueChanged = valueChanged;
+
+        /**
+         * Methods for checking correct input
+         */
+        function valueChanged(){
+            $scope.type.setLeafValue($scope.type.bitsValues);
+            $scope.node.checkValueType();
+            $scope.node.fill($scope.node.label, $scope.node.value);
+            $scope.buildRootRequest();
+        }
+    }
+});
+
diff --git a/modules/yangman-resources/src/main/resources/yangman/controllers/form/ym-type-boolean.controller.js b/modules/yangman-resources/src/main/resources/yangman/controllers/form/ym-type-boolean.controller.js
new file mode 100644 (file)
index 0000000..2c575fe
--- /dev/null
@@ -0,0 +1,18 @@
+define([], function () {
+    'use strict';
+
+    angular.module('app.yangman').controller('YMTypeBooleanCtrl', YMTypeBooleanCtrl);
+
+    YMTypeBooleanCtrl.$inject = ['$scope'];
+
+    function YMTypeBooleanCtrl($scope){
+        var yangTypeBolean = this;
+
+        $scope.$watch('node.value', function(){
+            if ( typeof $scope.node.value !== 'boolean' && $scope.node.value.length) {
+                $scope.node.value = $scope.node.value === 'true';
+            }
+        });
+    }
+});
+
diff --git a/modules/yangman-resources/src/main/resources/yangman/controllers/form/ym-type-empty.controller.js b/modules/yangman-resources/src/main/resources/yangman/controllers/form/ym-type-empty.controller.js
new file mode 100644 (file)
index 0000000..537562b
--- /dev/null
@@ -0,0 +1,22 @@
+define([], function () {
+    'use strict';
+
+    angular.module('app.yangman').controller('YMTypeEmptyCtrl', YMTypeEmptyCtrl);
+
+    YMTypeEmptyCtrl.$inject = ['$scope'];
+
+    function YMTypeEmptyCtrl($scope){
+        var yangTypeEmpty = this;
+        // methods
+        yangTypeEmpty.valueChanged = valueChanged;
+
+        /**
+         * Methods for checking correct input
+         */
+        function valueChanged(){
+            $scope.buildRootRequest();
+        }
+    }
+});
+
+
diff --git a/modules/yangman-resources/src/main/resources/yangman/controllers/form/ym-type-enum.controller.js b/modules/yangman-resources/src/main/resources/yangman/controllers/form/ym-type-enum.controller.js
new file mode 100644 (file)
index 0000000..da507b5
--- /dev/null
@@ -0,0 +1,27 @@
+define([], function () {
+    'use strict';
+
+    angular.module('app.yangman').controller('YMTypeEnumCtrl', YMTypeEnumCtrl);
+
+    YMTypeEnumCtrl.$inject = ['$scope'];
+
+    function YMTypeEnumCtrl($scope){
+        var yangTypeEnum = this;
+
+        // methods
+        yangTypeEnum.valueChanged = valueChanged;
+
+        /**
+         * Methods for checking correct input
+         */
+        function valueChanged(){
+            var value = $scope.type.selEnum && $scope.type.selEnum.label ? $scope.type.selEnum.label : '';
+
+            $scope.type.setLeafValue(value);
+            $scope.node.checkValueType();
+            $scope.node.fill($scope.node.label, $scope.node.value);
+            $scope.buildRootRequest();
+        }
+    }
+});
+
diff --git a/modules/yangman-resources/src/main/resources/yangman/controllers/form/ym-type.controller.js b/modules/yangman-resources/src/main/resources/yangman/controllers/form/ym-type.controller.js
new file mode 100644 (file)
index 0000000..4728028
--- /dev/null
@@ -0,0 +1,23 @@
+define([], function () {
+    'use strict';
+
+    angular.module('app.yangman').controller('YMTypeCtrl', YMTypeCtrl);
+
+    YMTypeCtrl.$inject = ['$scope'];
+
+    function YMTypeCtrl($scope){
+        var yangType = this;
+
+        // methods
+        yangType.valueChanged = valueChanged;
+
+        /**
+         * Methods for checking correct input
+         */
+        function valueChanged(){
+            $scope.node.checkValueType();
+            $scope.node.fill($scope.node.label, $scope.node.value);
+            $scope.buildRootRequest();
+        }
+    }
+});
diff --git a/modules/yangman-resources/src/main/resources/yangman/controllers/module-detail.controller.js b/modules/yangman-resources/src/main/resources/yangman/controllers/module-detail.controller.js
new file mode 100644 (file)
index 0000000..5c2168c
--- /dev/null
@@ -0,0 +1,63 @@
+define([
+    'app/yangman/directives/abn-tree.directive',
+], function () {
+    'use strict';
+
+    angular.module('app.yangman').controller('ModuleDetailCtrl', ModuleDetailCtrl);
+
+    ModuleDetailCtrl.$inject = ['$scope', '$rootScope', '$timeout', 'YangmanService', 'constants'];
+
+    function ModuleDetailCtrl($scope, $rootScope, $timeout, YangmanService, constants) {
+        var moduleDetail = this;
+
+        moduleDetail.treeApis = [];
+        moduleDetail.selectedInnerDatastore = null;
+
+        // methods
+        moduleDetail.setApiNode = setApiNode;
+        moduleDetail.setDataDetailStore = setDataDetailStore;
+
+        // WATCHERS
+        $scope.$on(constants.YANGMAN_MODULE_D_INIT, function (){
+            init();
+        });
+
+        /**
+         * Initialization
+         */
+        function init(){
+            $timeout(function () {
+                moduleDetail.selectedDataStoreIndex =
+                    YangmanService.getDataStoreIndex($scope.selectedModule.children, $scope.selectedDatastore.label);
+                moduleDetail.treeApis = $scope.selectedDatastore.children;
+            });
+        }
+
+        /**
+         * Set global selected yang node
+         * @param apiIndex
+         * @param subApiIndex
+         */
+        function setApiNode(apiIndex, subApiIndex){
+
+            if (apiIndex !== undefined && subApiIndex !== undefined ) {
+
+                $scope.setApi($scope.apis[apiIndex], $scope.apis[apiIndex].subApis[subApiIndex], true, true);
+                $scope.setNode($scope.selectedSubApi.node);
+                $scope.clearCM();
+            }
+        }
+
+        /**
+         * Set datastore to global param
+         * @param dataStore
+         */
+        function setDataDetailStore(dataStore){
+            $scope.setDataStore(dataStore);
+            $scope.setApi($scope.selectedApi, null);
+            $scope.setNode(null);
+            moduleDetail.treeApis = dataStore.children;
+        }
+    }
+
+});
diff --git a/modules/yangman-resources/src/main/resources/yangman/controllers/modules-list.controller.js b/modules/yangman-resources/src/main/resources/yangman/controllers/modules-list.controller.js
new file mode 100644 (file)
index 0000000..c686d34
--- /dev/null
@@ -0,0 +1,152 @@
+define([
+    'app/yangman/services/plugins-handler.services',
+], function () {
+    'use strict';
+
+    angular.module('app.yangman').controller('ModulesListCtrl', ModulesListCtrl);
+
+    ModulesListCtrl.$inject = ['$scope', '$rootScope', '$mdToast', 'YangUtilsService', 'PluginsHandlerService',
+                                '$filter', '$timeout', 'constants'];
+
+    function ModulesListCtrl($scope, $rootScope, $mdToast, YangUtilsService, PluginsHandlerService, $filter, $timeout, constants) {
+        var modulesList = this;
+
+        modulesList.treeApis = [];
+        modulesList.showLoadingBox = true;
+        modulesList.moduleListTitle = '';
+        modulesList.search = '';
+
+        // methods
+        modulesList.clearFilter = clearFilter;
+        modulesList.customSearch = customSearch;
+        modulesList.checkSelectedModule = checkSelectedModule;
+        modulesList.setDataStore = setDataStore;
+        modulesList.setModule = setModule;
+
+        // watchers
+        $scope.$on(constants.YANGMAN_GET_API_TREE_DATA, function (event, args) {
+            (args.cbk || angular.noop)(modulesList.treeApis);
+        });
+
+        // set tree apis data
+        $scope.$on(constants.YANGMAN_SET_API_TREE_DATA, function (event, args) {
+            modulesList.treeApis = args.params;
+            modulesList.showLoadingBox = false;
+            showToastInfoBox('YANGMAN_LOADED_MODULES');
+        });
+
+        // show hide loading box
+        $scope.$on(constants.YANGMAN_SET_LOADING_BOX, function (event, args){
+            modulesList.showLoadingBox = args.params;
+            (args.cbk || angular.noop)();
+        });
+
+        // show info box with custom title
+        $scope.$on(constants.YANGMAN_SHOW_TOAST, function (event, args) {
+            showToastInfoBox(args.params);
+        });
+
+        $scope.$on(constants.YANGMAN_SET_MODULE_LIST_TITLE, function (event, args) {
+            modulesList.moduleListTitle = args.params;
+        });
+
+        /**
+         * Initialization
+         */
+        function init(){
+            loadApis();
+        }
+
+        init();
+
+        /**
+         * Check if module and one of it datastore is selected
+         * @param module
+         * @returns {boolean|*|Function|o}
+         */
+        function checkSelectedModule(module){
+            var haveSelectedDS = [];
+
+            if ( $scope.selectedDatastore && (module === $scope.selectedModule)) {
+                haveSelectedDS = $scope.selectedModule.children.filter(function(item){
+                    return item === $scope.selectedDatastore;
+                });
+            }
+
+            return haveSelectedDS.length;
+        }
+
+        /**
+         * Custom search function for searching by api label
+         * @param api
+         */
+        function customSearch(api){
+            return api.label.toLowerCase().indexOf(modulesList.search.toLowerCase()) > -1;
+        }
+
+        /**
+         * Clear current ctrl search value
+         */
+        function clearFilter(){
+            modulesList.search = '';
+        }
+
+        /**
+         * Load apis and modules
+         */
+        function loadApis() {
+            modulesList.allNodes = [];
+            modulesList.treeApis = [];
+
+            modulesList.showLoadingBox = true;
+
+            YangUtilsService.generateNodesToApis(function (apis, allNodes, augGroups) {
+                $scope.setGlobalParams(apis, augGroups);
+                modulesList.allNodes = allNodes;
+                modulesList.treeApis = YangUtilsService.generateApiTreeData(apis);
+                modulesList.showLoadingBox = false;
+                showToastInfoBox('YANGMAN_LOADED_MODULES');
+
+                PluginsHandlerService.plugAll(apis, modulesList);
+            }, function () {
+                showToastInfoBox('YANGMAN_LOADED_MODULES_ERROR');
+                modulesList.showLoadingBox = false;
+            });
+        }
+
+        /**
+         * Set and expand module in tree
+         */
+        function setModule(module, e){
+            if ( angular.element(e.target).hasClass('top-element') ) {
+                module.expanded = !module.expanded;
+            }
+        }
+
+        /**
+         * Set data store || rpc
+         * @param dataStore
+         * @param module
+         */
+        function setDataStore(dataStore, module){
+            $scope.setModule(module);
+            $scope.setDataStore(dataStore, true, 1);
+        }
+
+        /**
+         * Method for showing toast box
+         * @param text
+         */
+        function showToastInfoBox(text){
+            $timeout(function(){
+                $mdToast.show(
+                    $mdToast.simple()
+                        .textContent($filter('translate')(text))
+                        .position('bottom left')
+                        .parent(angular.element('.yangmanModule__left-panel'))
+                        .hideDelay(3000)
+                );
+            }, 500);
+        }
+    }
+});
diff --git a/modules/yangman-resources/src/main/resources/yangman/controllers/params-admin.controller.js b/modules/yangman-resources/src/main/resources/yangman/controllers/params-admin.controller.js
new file mode 100644 (file)
index 0000000..4d5fcf4
--- /dev/null
@@ -0,0 +1,208 @@
+define([
+    'app/yangman/services/handle-file.services',
+], function () {
+    'use strict';
+
+    angular.module('app.yangman').controller('ParamsAdminCtrl', ParamsAdminCtrl);
+
+    ParamsAdminCtrl.$inject = ['$mdMenu', '$mdDialog', '$scope', '$timeout', 'YangmanService', 'YMHandleFileService', 'parametersList'];
+
+    function ParamsAdminCtrl($mdMenu, $mdDialog, $scope, $timeout, YangmanService, YMHandleFileService, parametersList) {
+        var openMenuListener,
+            vm = this;
+
+        vm.parametersList = parametersList;
+        vm.search = '';
+        vm.sortField1 = '_name';
+        vm.sortField2 = '_value';
+        vm.sortAsc = true;
+
+        vm.close = close;
+        vm.save = save;
+        vm.createEmptyParam = createEmptyParam;
+        vm.removeParam = removeParam;
+        vm.clearFilter = clearFilter;
+        vm.filterParam = filterParam;
+        vm.sortBy = sortBy;
+        vm.sortFunc = sortFunc;
+        vm.exportParameters = exportParameters;
+        vm.importParameters = importParameters;
+        vm.validateNamesUnique = validateNamesUnique;
+        vm.filterChange = filterChange;
+
+        init();
+
+
+        /**
+         * Force validation after some filter is applied
+         */
+        function filterChange() {
+            $timeout(vm.validateNamesUnique);
+        }
+
+        /**
+         * Loop over all name inputs in form and validate duplicities
+         */
+        function validateNamesUnique() {
+            var i = 0;
+            while (vm.paramsForm.hasOwnProperty('name_' + i)){
+                var modelValue = vm.paramsForm['name_' + i].$modelValue;
+                vm.paramsForm['name_' + i].$setValidity(
+                    'unique',
+                    vm.parametersList.isNameUnique(modelValue)
+                );
+                i++;
+            }
+        }
+
+        /**
+         * Importing all parameters from json
+         * @param fileContent
+         */
+        function importParameters(fileContent) {
+            if (fileContent && YangmanService.validateFile(fileContent, ['name', 'value'])){
+                try {
+                    vm.parametersList.createParamsFromJson(fileContent);
+                    vm.parametersList.saveToStorage();
+                    angular.element(document).find('#importParameters').val('');
+                    createEmptyParam();
+                }
+                catch (e) {
+                    angular.element(document).find('#importParameters').val('');
+                    console.error('DataStorage error:', e);
+                }
+            }
+            else {
+                angular.element(document).find('#importParameters').val('');
+            }
+
+        }
+
+        /**
+         * Export all parameters to json file
+         */
+        function exportParameters() {
+
+            YMHandleFileService.downloadFile(
+                'yangman_parameters.json',
+                vm.parametersList.toJSON(),
+                'json',
+                'charset=utf-8',
+                function (){},
+                function (e){
+                    console.error('Export parameters error:', e);
+                }
+            );
+        }
+
+        /**
+         * Set attribute to use when sorting
+         * @param sortField1 , sortField2
+         */
+        function sortBy(sortField1, sortField2) {
+            vm.sortField1 = sortField1;
+            vm.sortField2 = sortField2;
+            vm.sortAsc = !vm.sortAsc;
+            vm.parametersList.applyValsForFilters();
+            $timeout(vm.validateNamesUnique);
+        }
+
+        /**
+         * Sort parameters with empty params at the end of list
+         * @param item
+         * @returns {*}
+         */
+        function sortFunc(item) {
+            return [item[vm.sortField1] ? item[vm.sortField1] : (vm.sortAsc ? String.fromCharCode(255) : ''),
+                    item[vm.sortField2] ? item[vm.sortField2] : (vm.sortAsc ? String.fromCharCode(255) : '')];
+        }
+
+        /**
+         * Empty or matching params will be in list
+         * @param paramObj
+         * @returns {boolean}
+         */
+        function filterParam(paramObj) {
+            return !(paramObj._name || paramObj._value) ||
+                (paramObj._name && paramObj._name.indexOf(vm.search) !== -1) ||
+                (paramObj._value && paramObj._value.indexOf(vm.search) !== -1);
+        }
+
+
+        function clearFilter() {
+            vm.search = '';
+        }
+
+        /**
+         * Load params list and add one empty to the end of list
+         */
+        function init(){
+            vm.parametersList.loadListFromStorage();
+            createEmptyParam();
+            openMenuListener = $scope.$on('$mdMenuOpen', function () {
+                closeOpenedMenu();
+                $timeout(registerClickOutside);
+            });
+        }
+
+        /**
+         * Remove param from list
+         * @param paramObj
+         */
+        function removeParam(paramObj) {
+            vm.parametersList.deleteParameterItem(paramObj);
+            $timeout(vm.validateNamesUnique);
+        }
+
+        /**
+         * Create new empty param
+         */
+        function createEmptyParam() {
+            vm.parametersList.addEmptyItem();
+        }
+
+        /**
+         * Cancel dialog
+         */
+        function close() {
+            vm.parametersList.removeEmptyParams();
+            $mdDialog.hide();
+        }
+
+        /**
+         * Save list to storage and re-init dialog
+         */
+        function save() {
+            vm.parametersList.saveToStorage();
+            init();
+        }
+
+        function registerClickOutside() {
+            $(document).click(function () {
+                closeOpenedMenu();
+            });
+        }
+
+        function unregisterClickOutside() {
+            $(document).off('click');
+        }
+
+        function openMenuDestroyListener() {
+            $scope.$on('$destroy', function () {
+                openMenuListener();
+            });
+        }
+
+        function closeOpenedMenu() {
+            unregisterClickOutside();
+            openMenuDestroyListener();
+            $mdMenu.hide();
+        }
+
+
+
+    }
+
+    return ParamsAdminCtrl;
+
+});
diff --git a/modules/yangman-resources/src/main/resources/yangman/controllers/request-data.controller.js b/modules/yangman-resources/src/main/resources/yangman/controllers/request-data.controller.js
new file mode 100644 (file)
index 0000000..2064d37
--- /dev/null
@@ -0,0 +1,140 @@
+define([], function () {
+    'use strict';
+
+    angular.module('app.yangman').controller('RequestDataCtrl', RequestDataCtrl);
+
+    RequestDataCtrl.$inject = ['$filter', '$mdToast', '$scope', 'RequestsService', 'constants'];
+
+    function RequestDataCtrl($filter, $mdToast, $scope, RequestsService, constants) {
+        var requestData = this,
+            cmData = {
+                cmInstance: null,
+                cmFontSize: 14,
+            };
+
+        requestData.paramsArray = [];
+        requestData.data = '';
+        requestData.type = null;
+
+
+        // todo: move all cm staff to directive
+        requestData.dataEditorOptions = {
+            mode: 'javascript',
+            lineNumbers: true,
+            lineWrapping: true,
+            matchBrackets: true,
+            extraKeys: {
+                'Ctrl-Space': 'autocomplete',
+            },
+            onLoad: function (cmInstance) {
+
+                cmData.cmInstance = cmInstance;
+
+                cmInstance.data = {
+                    parameterListObj: $scope.parametersList,
+                };
+
+                angular.element(cmInstance.display.wrapper).css('fontSize', cmData.cmFontSize + 'px');
+
+                cmInstance.on('changes', function () {
+                    if (angular.isFunction(cmInstance.showHint)) {
+                        cmInstance.showHint();
+                    }
+                });
+
+                cmInstance.on('cursorActivity', function () {
+                    var lineString = cmInstance.getLine(cmInstance.getCursor().line);
+                    requestData.paramsArray = RequestsService.scanDataParams($scope.parametersList, lineString);
+
+                    if (!$scope.$$phase) {
+                        $scope.$apply();
+                    }
+                });
+
+                cmInstance.on('keydown', function (codemirror, event) {
+                    if (event.altKey) {
+                        switch (event.key){
+                            case '+':
+                                incCMFontSize();
+                                angular.element(cmInstance.display.wrapper).css(
+                                    'fontSize',
+                                    cmData.cmFontSize + 'px'
+                                );
+                                break;
+                            case '-':
+                                decCMFontSize();
+                                angular.element(cmInstance.display.wrapper).css(
+                                    'fontSize',
+                                    cmData.cmFontSize + 'px'
+                                );
+                                break;
+                        }
+
+                    }
+                });
+
+
+            },
+        };
+
+        // methods
+        requestData.init = init;
+        requestData.enlargeCMFont = enlargeCMFont;
+        requestData.reduceCMFont = reduceCMFont;
+
+        function incCMFontSize() {
+            if (cmData.cmFontSize < 30) {
+                cmData.cmFontSize++;
+            }
+        }
+
+        function decCMFontSize() {
+            if (cmData.cmFontSize > 5) {
+                cmData.cmFontSize--;
+            }
+        }
+
+        function enlargeCMFont() {
+            incCMFontSize();
+            angular.element(cmData.cmInstance.display.wrapper).css(
+                'fontSize',
+                cmData.cmFontSize + 'px'
+            );
+        }
+
+        function reduceCMFont() {
+            decCMFontSize();
+            angular.element(cmData.cmInstance.display.wrapper).css(
+                'fontSize',
+                cmData.cmFontSize + 'px'
+            );
+        }
+
+        /**
+         * Set code mirror theme and readonly property considering requestData.type
+         */
+        function initEditorOptions() {
+            requestData.dataEditorOptions.theme = requestData.type === constants.REQUEST_DATA_TYPE_RECEIVED ? 'eclipse-disabled' : 'eclipse';
+            requestData.dataEditorOptions.readOnly = requestData.type === constants.REQUEST_DATA_TYPE_RECEIVED;
+        }
+
+
+        /**
+         * Initialization
+         * @param type
+         */
+        function init(type){
+            requestData.type = type;
+            initEditorOptions();
+
+            $scope.$on(constants.YANGMAN_SET_CODEMIRROR_DATA + type, function (event, args){
+                requestData.data = args.params.data;
+            });
+
+            $scope.$on(constants.YANGMAN_GET_CODEMIRROR_DATA + type, function (event, args){
+                args.params.reqData = requestData.data;
+            });
+        }
+    }
+
+});
diff --git a/modules/yangman-resources/src/main/resources/yangman/controllers/request-header.controller.js b/modules/yangman-resources/src/main/resources/yangman/controllers/request-header.controller.js
new file mode 100644 (file)
index 0000000..f6e593a
--- /dev/null
@@ -0,0 +1,579 @@
+define([
+    'app/yangman/controllers/params-admin.controller',
+    'app/yangman/services/time-tracking.services',
+], function (ParamsAdminCtrl) {
+    'use strict';
+
+    angular.module('app.yangman').controller('RequestHeaderCtrl', RequestHeaderCtrl);
+
+    RequestHeaderCtrl.$inject = [
+        '$mdDialog', '$mdToast', '$scope', '$rootScope', 'ENV', 'YangmanService', 'ParametersService',
+        'PathUtilsService', 'RequestsService', '$filter', 'DataBackupService', 'constants', 'TimeTrackingService'
+    ];
+
+    function RequestHeaderCtrl($mdDialog, $mdToast, $scope, $rootScope, ENV, YangmanService, ParametersService,
+                               PathUtilsService, RequestService, $filter, DataBackupService, constants,
+                               TimeTrackingService) {
+        var requestHeader = this;
+
+        requestHeader.allOperations = [constants.OPERATION_GET, constants.OPERATION_POST, constants.OPERATION_PUT, constants.OPERATION_DELETE];
+        requestHeader.constants = constants;
+        requestHeader.urlChanged = false;
+        requestHeader.executedOperation = null;
+        requestHeader.selectedOperationsList = [];
+        requestHeader.selectedOperation = null;
+        requestHeader.requestUrl = '';
+        requestHeader.selectedPluginsButtons = [];
+        requestHeader.selectedPlugin = null;
+        requestHeader.statusObj = null;
+
+        // methods
+        requestHeader.executeOperation = executeOperation;
+        requestHeader.executePluginFunctionality = executePluginFunctionality;
+        requestHeader.fillNodeData = fillNodeData;
+        requestHeader.changeDataType = changeDataType;
+        requestHeader.prepareDataAndExecute = prepareDataAndExecute;
+        requestHeader.initMountPoint = initMountPoint;
+        requestHeader.setJsonView = setJsonView;
+        requestHeader.setRequestUrl = setRequestUrl;
+        requestHeader.showParamsAdmin = showParamsAdmin;
+        requestHeader.saveRequestToCollection = saveRequestToCollection;
+        requestHeader.unsetPluginFunctionality = unsetPluginFunctionality;
+
+        // watchers
+        /**
+         * Set selected operations based on data store
+         */
+        $scope.$on(constants.SET_SEL_OPERATIONS, function (event, operations, setUrl) {
+            setAllowedMethods(operations);
+
+            if ( setUrl ) {
+                setRequestUrl();
+            }
+        });
+
+        /**
+         * Watching for changes in shown detail data type (radio button)
+         */
+        $scope.$on(constants.YANGMAN_HEADER_INIT, function (event, args) {
+            init();
+            setRequestUrl(args.params.path);
+            setRequestMethod(args.params.method);
+            setRequestStatus(args.params.statusObj);
+            setJsonView();
+            (args.cbk || angular.noop)();
+        });
+
+        $scope.$on(constants.YANGMAN_FILL_NODE_FROM_REQ, function (event, args) {
+            setNodeDataFromRequestData(args.params.requestUrl, args.params.leftpanel);
+            (args.cbk || angular.noop)();
+        });
+
+        $scope.$on(constants.YANGMAN_EXECUTE_WITH_DATA, function (event, args) {
+            executeOperation(args.params.data ? angular.fromJson(args.params.data) : {}, args.cbk);
+        });
+
+        init();
+
+        /**
+         * Setter for selected operation
+         * @param method
+         */
+        function setRequestMethod(method){
+            requestHeader.selectedOperation = method;
+        }
+
+        /**
+         * Setter for request status
+         * @param statusObj
+         */
+        function setRequestStatus(statusObj){
+            requestHeader.statusObj = statusObj;
+        }
+
+        /**
+         * Show popup for parameters administration
+         * @param event
+         */
+        function showParamsAdmin(event) {
+            $mdDialog.show({
+                controller: ParamsAdminCtrl,
+                controllerAs: 'paramsAdmin',
+                templateUrl: $scope.globalViewPath + 'popup/parameters-admin.tpl.html',
+                parent: angular.element('#yangmanModule'),
+                targetEvent: event,
+                clickOutsideToClose: true,
+                locals: {
+                    parametersList: $scope.parametersList,
+                },
+            }).then(
+                function (){
+                    $scope.parametersList.loadListFromStorage();
+                },
+                function (){
+                    $scope.parametersList.loadListFromStorage();
+                }
+            );
+        }
+
+        /**
+         * Method for selecting correct json view by selected operation
+         */
+        function setJsonView(){
+            var both = [constants.OPERATION_PUT, constants.OPERATION_POST];
+
+            if ( both.indexOf(requestHeader.selectedOperation) > -1 ){
+                $scope.setJsonView(true, true);
+            } else {
+                $scope.setJsonView(true, false);
+            }
+        }
+
+        /**
+         * Change displayed data type to json or form, after switching set current data to be displayed
+         */
+        function changeDataType(){
+            $scope.switchSection('rightPanelSection', requestHeader.selectedShownDataType);
+
+            if(!$scope.node || requestHeader.urlChanged) {
+                requestHeader.setRequestUrl();
+                requestHeader.urlChanged = false;
+            }
+
+            // if changing to json, fill codemirror data
+            if ( requestHeader.selectedShownDataType === constants.DISPLAY_TYPE_REQ_DATA && $scope.node ){
+                setJsonView();
+                sendRequestData($scope.buildRootRequest(), 'SENT');
+            }
+
+            // if changing to form, try to fill node data
+            if (requestHeader.selectedShownDataType === constants.DISPLAY_TYPE_FORM) {
+                var reqData = {};
+
+                reqData = getDataForForm();
+                setNodeDataFromRequestData(requestHeader.requestUrl);
+
+                if ( $scope.node ) {
+
+                    YangmanService.fillNodeFromResponse($scope.node, reqData);
+                    $scope.node.expanded = true;
+                }
+            }
+        }
+
+        /**
+         * Helper method for building correct json data for form, rpc included
+         * @returns {*}
+         */
+        function getDataForForm(){
+            var params = {
+                    reqData: null,
+                },
+                dataTypeFunc = {
+                    rpc: function () {
+                        var sentData = { reqData: null },
+                            allData = { sent: null, received: null };
+
+                        $scope.rootBroadcast(constants.YANGMAN_GET_CODEMIRROR_DATA_RECEIVED, params);
+                        $scope.rootBroadcast(constants.YANGMAN_GET_CODEMIRROR_DATA_SENT, sentData);
+
+                        allData.sent = sentData.reqData ? angular.fromJson(sentData.reqData) : {};
+                        allData.received = params.reqData ? angular.fromJson(params.reqData) : {};
+
+                        return YangmanService.prepareReceivedData(
+                            $scope.node,
+                            requestHeader.selectedOperation,
+                            allData.received,
+                            allData.sent,
+                            requestHeader.selectedShownDataType
+                        );
+                    },
+                    default: function (){
+                        var dataType;
+                        if(requestHeader.executedOperation) {
+                            dataType = requestHeader.executedOperation === constants.OPERATION_GET ? constants.REQUEST_DATA_TYPE_RECEIVED : 'SENT';
+                        }
+                        else {
+                            dataType = requestHeader.selectedOperation === constants.OPERATION_GET ? constants.REQUEST_DATA_TYPE_RECEIVED : 'SENT';
+                        }
+
+                        $scope.rootBroadcast(constants.YANGMAN_GET_CODEMIRROR_DATA + dataType, params);
+                        return params.reqData ? angular.fromJson(params.reqData) : {};
+                    },
+                };
+
+            return $scope.node ? (dataTypeFunc[$scope.node.type] || dataTypeFunc.default)() : {};
+        }
+
+        /**
+         * Send data to codemirror
+         * @param data
+         */
+        function sendRequestData(data, type){
+            $scope.rootBroadcast(
+                constants.YANGMAN_SET_CODEMIRROR_DATA + type,
+                { data: data instanceof Object ? JSON.stringify(data, null, 4) : data }
+            );
+        }
+
+        function sendErrorData(response) {
+            $scope.rootBroadcast(constants.YANGMAN_SET_ERROR_DATA, response);
+        }
+
+        /**
+         * Create empty parameters list, load from local storage and set to $scope
+         */
+        function initParams(){
+            $scope.parametersList.loadListFromStorage();
+        }
+
+        /**
+         * Initialization
+         */
+        function init(){
+            setAllowedMethods(requestHeader.allOperations);
+            initParams();
+            requestHeader.selectedShownDataType = $scope.rightPanelSection;
+        }
+
+        /**
+         * Set allowed operations for request
+         * @param operations
+         */
+        function setAllowedMethods(operations){
+            requestHeader.selectedOperationsList = operations.length ? operations : requestHeader.allOperations;
+            if (operations.indexOf(requestHeader.selectedOperation) === -1){
+                requestHeader.selectedOperation = requestHeader.selectedOperationsList[0];
+            }
+        }
+
+        /**
+         * Set header request url if json selected
+         */
+        function setRequestUrl(path){
+            requestHeader.requestUrl = path || ($scope.selectedSubApi ?
+                    ENV.getBaseURL('MD_SAL') + '/restconf/' + $scope.selectedSubApi.buildApiRequestString() : '');
+        }
+
+
+        /**
+         * Try to set api, module, dataStore and node, if api indexes for request url available
+         * and set (or unset) module detail panel to be displayed
+         * @param requestUrl url to try to find
+         * @param leftpanel index of main left tabs to be displayed (we dont want to display module detail in all cases)
+         */
+        function setNodeDataFromRequestData(requestUrl, leftpanel){
+
+            setApiByUrl(requestUrl, function (treeApis) {
+                // set module
+                $scope.setModule($filter('filter')(treeApis, { label: $scope.selectedApi.module })[0]);
+
+                // set datastore
+                $scope.setDataStore(
+                    $filter('filter')(
+                        $scope.selectedModule.children,
+                        { label: $scope.selectedSubApi.storage })[0],
+                    true,
+                    leftpanel
+                );
+
+                // set node
+                $scope.setNode($scope.selectedSubApi.node);
+
+                // fill subapi path
+                PathUtilsService.fillPath($scope.selectedSubApi.pathArray, requestUrl);
+                setRequestUrl();
+            });
+        }
+
+        function setApiByUrl(url, cbk, fill){
+            $scope.rootBroadcast(constants.YANGMAN_GET_API_TREE_DATA, null, function (treeApis) {
+                var apisIndexes =
+                    PathUtilsService.searchNodeByPath(url, treeApis, null, true, true);
+
+                if ( apisIndexes ) {
+
+                    // set apis
+                    $scope.setApi(
+                        $scope.apis[apisIndexes.indexApi],
+                        $scope.apis[apisIndexes.indexApi].subApis[apisIndexes.indexSubApi]
+                    );
+
+                    if ( $scope.selectedSubApi && fill ) {
+                        var updatedUrl = YangmanService.cutUrl(url);
+                        PathUtilsService.fillPath($scope.selectedSubApi.pathArray, updatedUrl);
+
+                    }
+
+                    (cbk || angular.noop)(treeApis);
+                }
+            });
+        }
+
+        function saveRequestToCollection(event) {
+            var historyReq = null,
+                sentData = { reqData: null },
+                receivedData = { reqData: null };
+
+            if (requestHeader.selectedShownDataType === constants.DISPLAY_TYPE_FORM) {
+                requestHeader.setRequestUrl();
+            }
+
+            historyReq = RequestService.createHistoryRequest(
+                null, null, requestHeader.requestUrl, requestHeader.selectedOperation, '', '', ''
+            );
+
+            $scope.rootBroadcast(constants.YANGMAN_GET_CODEMIRROR_DATA_SENT, sentData);
+            $scope.rootBroadcast(constants.YANGMAN_GET_CODEMIRROR_DATA_RECEIVED, receivedData);
+
+            RequestService.fillRequestByMethod(
+                historyReq, sentData, receivedData, requestHeader.selectedOperation, $scope.node,
+                requestHeader.selectedShownDataType
+            );
+
+            $scope.rootBroadcast(constants.YANGMAN_SAVE_REQUEST_TO_COLLECTION, { event: event, reqObj: historyReq });
+        }
+
+        function showRequestProgress(){
+            $scope.rootBroadcast(constants.YANGMAN_EXECUTING_REQUEST_PROGRESS_START);
+        }
+
+
+        function finishRequestProgress(message){
+            $scope.rootBroadcast(constants.YANGMAN_EXECUTING_REQUEST_PROGRESS_STOP);
+        }
+
+        /**
+         * Execute request operation
+         */
+        function executeOperation(requestData, executeCbk){
+            TimeTrackingService.startTimer();
+            var allowExecuteOperation =
+                requestHeader.selectedShownDataType === constants.DISPLAY_TYPE_FORM && $scope.selectedSubApi ?
+                    !PathUtilsService.checkEmptyIdentifiers($scope.selectedSubApi.pathArray) : true;
+
+            if ( allowExecuteOperation ) {
+
+                showRequestProgress();
+                setRequestUrl(requestHeader.selectedShownDataType === constants.DISPLAY_TYPE_REQ_DATA ? requestHeader.requestUrl : null);
+                $scope.rootBroadcast(constants.YANGMAN_SET_ERROR_MESSAGE, '');
+
+                if ( requestHeader.selectedShownDataType !== constants.DISPLAY_TYPE_FORM ){
+                    setApiByUrl(requestHeader.requestUrl, null, true);
+                }
+
+                var historyReq = RequestService.createHistoryRequest(null, null, requestHeader.requestUrl,
+                    requestHeader.selectedOperation, '', '', '');
+
+                YangmanService.executeRequestOperation(
+                    $scope.selectedApi,
+                    $scope.selectedSubApi,
+                    requestHeader.selectedOperation,
+                    $scope.node,
+                    requestHeader.selectedShownDataType,
+                    requestHeader.requestUrl,
+                    requestData,
+                    $scope.parametersList,
+                    executeReqSuccCbk,
+                    executeReqErrCbk
+                );
+                requestHeader.executedOperation = requestHeader.selectedOperation;
+            } else {
+                $scope.rootBroadcast(
+                    constants.YANGMAN_SET_ERROR_MESSAGE,
+                    $filter('translate')(constants.YANGMAN_ERROR_EMPTY_IDENTIFIERS)
+                );
+            }
+
+            /**
+             * Success callback after executin operation
+             * @param reqInfo
+             * @param response
+             */
+            function executeReqSuccCbk(reqInfo, response) {
+                var preparedReceivedData = YangmanService.prepareReceivedData(
+                    $scope.node,
+                    requestHeader.selectedOperation,
+                    response.data ? response.data.plain() : {},
+                    reqInfo.requestSrcData,
+                    requestHeader.selectedShownDataType
+                );
+
+                finishRequestProgress();
+
+                requestHeader.statusObj = reqInfo;
+
+                sendErrorData({});
+
+                if (requestHeader.selectedShownDataType === constants.DISPLAY_TYPE_REQ_DATA){
+
+                    setNodeDataFromRequestData(requestHeader.requestUrl);
+                    sendRequestData(preparedReceivedData, constants.REQUEST_DATA_TYPE_RECEIVED);
+                    sendRequestData(reqInfo.requestSrcData || {}, 'SENT');
+                } else {
+
+                    if ($scope.node){
+
+                        YangmanService.fillNodeFromResponse($scope.node, preparedReceivedData);
+                        YangmanService.handleNodeIdentifier(
+                            $scope.parametersList, $scope.selectedSubApi, $scope.node
+                        );
+                        $scope.node.expanded = true;
+
+                        $scope.rootBroadcast(constants.YANGMAN_DISABLE_ADDING_LIST_ELEMENT);
+                        preparedReceivedData = YangmanService.checkRpcReceivedData(preparedReceivedData, $scope.node);
+                        sendRequestData(preparedReceivedData, constants.REQUEST_DATA_TYPE_RECEIVED);
+                    }
+                }
+
+                // create and set history request
+                requestHeader.statusObj.time = TimeTrackingService.returnTime();
+
+                historyReq.setExecutionData(
+                    reqInfo.requestSrcData,
+                    preparedReceivedData,
+                    reqInfo.status,
+                    reqInfo.status,
+                    reqInfo.statusText,
+                    requestHeader.statusObj.time
+                );
+
+                $scope.rootBroadcast(constants.YANGMAN_SAVE_EXECUTED_REQUEST, historyReq, function (){
+                    $scope.rootBroadcast(constants.YANGMAN_SELECT_THE_NEWEST_REQUEST);
+                });
+
+                (executeCbk || angular.noop)(historyReq);
+
+
+            }
+
+            /**
+             * Error callback after executin operation
+             * @param reqInfo
+             * @param response
+             */
+            function executeReqErrCbk(reqInfo, response) {
+                requestHeader.statusObj = reqInfo;
+
+                finishRequestProgress();
+
+                requestHeader.statusObj.time = TimeTrackingService.returnTime();
+
+                historyReq.setExecutionData(
+                    reqInfo.requestSrcData,
+                    response.data,
+                    reqInfo.status,
+                    reqInfo.status,
+                    reqInfo.statusText,
+                    requestHeader.statusObj.time
+                );
+                $scope.rootBroadcast(constants.YANGMAN_SAVE_EXECUTED_REQUEST, historyReq, function (){
+                    $scope.rootBroadcast(constants.YANGMAN_SELECT_THE_NEWEST_REQUEST);
+                });
+
+                if (response.data) {
+                    // try to fill code mirror editor
+                    sendRequestData(response.data, constants.REQUEST_DATA_TYPE_RECEIVED);
+                    sendErrorData(response.data);
+                }
+
+                (executeCbk || angular.noop)(historyReq);
+
+
+            }
+
+        }
+
+        /**
+         * TODO :: description
+         * @param pathElem
+         * @param identifier
+         */
+        function fillNodeData(pathElem, identifier) {
+            if ($scope.selectedSubApi && $scope.selectedSubApi.storage === constants.DATA_STORE_CONFIG &&
+                $scope.selectedSubApi.pathArray.indexOf(pathElem) === ($scope.selectedSubApi.pathArray.length - 1)) {
+                PathUtilsService.fillListNode($scope.node, identifier.label, identifier.value);
+            }
+
+            requestHeader.urlChanged = true;
+        }
+
+        /**
+         * Check data before executin operations
+         */
+        function prepareDataAndExecute(cbk){
+            if (requestHeader.statusObj) {
+                requestHeader.statusObj.statusText = null;
+                requestHeader.statusObj.time = null;
+            }
+
+            if ( requestHeader.requestUrl.length ) {
+
+                if ( requestHeader.selectedShownDataType === constants.DISPLAY_TYPE_REQ_DATA ) {
+                    // get json data
+                    var params = { reqData: null };
+                    $scope.rootBroadcast(constants.YANGMAN_GET_CODEMIRROR_DATA_SENT, params);
+                    executeOperation(params.reqData ? angular.fromJson(params.reqData) : {}, cbk);
+                } else {
+                    executeOperation({}, cbk);
+                }
+            }
+        }
+
+        /**
+         * Mount point initialization
+         * @param mountPointStructure
+         * @param mountPointTreeApis
+         * @param mountPointApis
+         * @param augmentations
+         */
+        function initMountPoint(mountPointTreeApis, mountPointApis, augmentations, reqObj){
+            DataBackupService.storeFromScope(
+                [
+                    'selectedDatastore', 'node', 'apis',
+                    'selectedApi', 'selectedSubApi', 'augmentations', 'selectedModule',
+                ],
+                $scope,
+                'MAIN_SCOPE'
+            );
+
+            $scope.rootBroadcast(constants.YANGMAN_GET_API_TREE_DATA, null, function (treeApis) {
+                DataBackupService.storeFromScope(
+                    ['treeApis'],
+                    { treeApis: treeApis },
+                    'MODULES_LIST'
+                );
+            });
+
+            $scope.setNode(null);
+            $scope.setModule(null);
+            $scope.setGlobalParams(mountPointApis, augmentations);
+            $scope.setDataStore(null);
+            requestHeader.statusObj = reqObj;
+            $scope.rootBroadcast(constants.YANGMAN_SET_API_TREE_DATA, mountPointTreeApis);
+        }
+
+        /**
+         * Executing custom plugin callback
+         * @param customPlugin
+         */
+        function executePluginFunctionality(customPlugin){
+            requestHeader.selectedPlugin = customPlugin;
+            customPlugin.runCallback({ scope: $scope, controller: requestHeader });
+        }
+
+        /**
+         * Unset custom plugin functionality - get back major params from scope
+         */
+        function unsetPluginFunctionality(){
+            if ( requestHeader.selectedPlugin ) {
+                $scope.unsetPlugin(requestHeader);
+            }
+
+            requestHeader.selectedPlugin = null;
+            requestHeader.selectedPluginsButtons = [];
+        }
+
+    }
+
+});
diff --git a/modules/yangman-resources/src/main/resources/yangman/controllers/requests-list.controller.js b/modules/yangman-resources/src/main/resources/yangman/controllers/requests-list.controller.js
new file mode 100644 (file)
index 0000000..fdf08ab
--- /dev/null
@@ -0,0 +1,642 @@
+define([
+    'app/yangman/controllers/save-req-dialog.controller',
+    'app/yangman/controllers/edit-collection-dialog.controller',
+    'app/yangman/services/handle-file.services',
+], function (SaveReqDialogCtrl, EditCollectionDialogCtrl) {
+    'use strict';
+
+    angular.module('app.yangman').controller('RequestsListCtrl', RequestsListCtrl);
+
+    RequestsListCtrl.$inject = [
+        '$filter', '$mdDialog', '$scope', 'YMHandleFileService', 'PathUtilsService', 'RequestsService', 'YangmanService',
+        'YangmanDesignService', 'constants',
+    ];
+
+    /**
+     * Controller for requests lists, means History requests and Collections requests
+     * @param $filter
+     * @param $mdDialog
+     * @param $scope
+     * @param YMHandleFileService
+     * @param PathUtilsService
+     * @param RequestsService
+     * @param YangmanService
+     * @param YangmanDesignService
+     * @constructor
+     */
+    function RequestsListCtrl($filter, $mdDialog, $scope, YMHandleFileService, PathUtilsService, RequestsService,
+                              YangmanService, YangmanDesignService, constants) {
+        var vm = this;
+
+        /**
+         * List of all collections containing requests, loads even for history controller to use collection names
+         * in saving requests dialog
+         * @type {*|CollectionList}
+         */
+        vm.collectionList = null;
+        vm.constants = constants;
+
+        /**
+         *
+         * @type {*|HistoryList}
+         */
+        vm.requestList = null;
+        vm.mainList = null;
+        vm.collectionsSortAsc = true;
+        vm.search = '';
+
+        // methods
+        vm.clearCollectionList = clearCollectionList;
+        vm.clearFilter = clearFilter;
+        vm.clearHistoryList = clearHistoryList;
+        vm.colMatchingReqsCount = colMatchingReqsCount;
+        vm.deselectAllFilteredRequests = deselectAllFilteredReqs;
+        vm.downloadCollection = downloadCollection;
+        vm.executeRequest = executeRequest;
+        vm.fakeFilter = fakeFilter;
+        vm.filterCol = filterCol;
+        vm.filterColName = filterColName;
+        vm.filterReq = filterReq;
+        vm.init = init;
+        vm.readCollectionFromFile = readCollectionFromFile;
+        vm.selectAllFilteredRequests = selectAllFilteredReqs;
+        vm.selectRequest = selectRequest;
+        vm.showData = showData;
+        vm.showDgDeleteCollection = showDgDeleteCollection;
+        vm.showDgDeleteRequests = showDgDeleteRequests;
+        vm.showDgEditCollection = showDgEditCollection;
+        vm.showDgSaveReq = showDgSaveReq;
+        vm.showForm = showForm;
+        vm.toggleCollectionsSort = toggleCollectionsSort;
+        vm.selectOnlyThisRequest = selectOnlyThisRequest;
+        vm.deselectAllRequests = deselectAllRequests;
+        vm.filterCollReq = filterCollReq;
+
+        /**
+         * Save request obje to collection from other controller
+         * @param reqObj
+         */
+        function saveRequestFromExt(event, args) {
+            vm.showDgSaveReq(args.params.event, args.params.reqObj, false);
+        }
+
+
+        /**
+         * Clear history requests list and save to storage
+         */
+        function clearHistoryList(event) {
+
+            YangmanDesignService.disableMdMenuItem(event);
+
+            var confirm = $mdDialog.confirm()
+                .title($filter('translate')('YANGMAN_DELETE_HISTORY_CONFIRM_TITLE'))
+                .textContent($filter('translate')('YANGMAN_DELETE_HISTORY_CONFIRM_TEXT'))
+                .ariaLabel($filter('translate')('YANGMAN_DELETE_HISTORY_CONFIRM_TITLE'))
+                .targetEvent(event)
+                .ok($filter('translate')('YANGMAN_OK'))
+                .cancel($filter('translate')('YANGMAN_CANCEL'));
+
+            $mdDialog.show(confirm).then(function (){
+                vm.requestList.clear();
+                vm.requestList.saveToStorage();
+                loadHistoryList();
+                YangmanDesignService.enableMdMenuItem(event);
+            }, function (){
+                YangmanDesignService.enableMdMenuItem(event);
+            });
+        }
+
+        /**
+         * Clear collections requests list and save to storage
+         */
+        function clearCollectionList(event) {
+            var confirm = $mdDialog.confirm()
+                .title($filter('translate')('YANGMAN_DELETE_COLLECTION_CONFIRM_TITLE'))
+                .textContent($filter('translate')('YANGMAN_DELETE_COLLECTION_CONFIRM_TEXT'))
+                .ariaLabel($filter('translate')('YANGMAN_DELETE_COLLECTION_CONFIRM_TITLE'))
+                .targetEvent(event)
+                .ok($filter('translate')('YANGMAN_OK'))
+                .cancel($filter('translate')('YANGMAN_CANCEL'));
+
+            YangmanDesignService.disableMdMenuItem(event);
+
+            $mdDialog.show(confirm).then(function (){
+                vm.collectionList.clear();
+                vm.collectionList.saveToStorage();
+                $scope.rootBroadcast(constants.YANGMAN_REFRESH_COLLECTIONS);
+                YangmanDesignService.enableMdMenuItem(event);
+            }, function () {
+                YangmanDesignService.enableMdMenuItem(event);
+            });
+        }
+
+        /**
+         * Create history request from other ctrl
+         * @param broadcastEvent
+         * @param params
+         */
+        function saveBcstedHistoryRequest(broadcastEvent, params) {
+            vm.requestList.addItemToList(params.params);
+            vm.requestList.saveToStorage();
+            (params.cbk || angular.noop)();
+        }
+
+        /**
+         * Clear value of input file used to import collection
+         * todo: move to design utils
+         */
+        function clearFileInputValue(){
+            angular.element(document).find('#importCollection').val('');
+        }
+
+        /**
+         * Importing collection from a file
+         * todo: error handling - msgs for user
+         * @param $fileContent
+         */
+        function readCollectionFromFile($fileContent) {
+            var data = $fileContent;
+
+            if (data && YangmanService.validateFile(data, constants.COLLECTION_CHECK_ARRAY)){
+                try {
+                    vm.collectionList.loadListFromFile(data);
+                    vm.collectionList.saveToStorage();
+                    $scope.rootBroadcast(constants.YANGMAN_REFRESH_COLLECTIONS);
+                    clearFileInputValue();
+                }
+                catch (e) {
+                    clearFileInputValue();
+                    console.error('DataStorage error:', e);
+                }
+            }
+            else {
+                clearFileInputValue();
+            }
+            removeButtonBackground();
+
+            function removeButtonBackground() {
+                $('#importCollection').next().css({ 'background': 'transparent' });
+            }
+        }
+
+        function toggleCollectionsSort() {
+            vm.collectionsSortAsc = !vm.collectionsSortAsc;
+        }
+
+        /**
+         * Export collection to json file
+         * @param {Collection} collection
+         */
+        function downloadCollection(collection) {
+
+            var cListJSON = vm.collectionList.getCollectionInRawJSON(collection.name);
+
+            YMHandleFileService.downloadFile(collection.name + '.json', cListJSON, 'json', 'charset=utf-8',
+                function (){},
+                function (e){
+                    console.error('ExportCollection error:', e);
+                }
+            );
+        }
+
+        /**
+         * Fill request form in right panel with request data
+         * @param reqObj
+         */
+        function showForm(reqObj) {
+            var data = reqObj.sentData;
+
+            // exception for get meth
+            if ( reqObj.method === constants.OPERATION_GET ) {
+                data = reqObj.receivedData;
+            }
+
+            $scope.rootBroadcast(
+                constants.YANGMAN_SET_CODEMIRROR_DATA_RECEIVED, { data: reqObj.setDataForView(reqObj.receivedData) }
+            );
+            $scope.rootBroadcast(
+                constants.YANGMAN_SET_CODEMIRROR_DATA_SENT, { data: reqObj.setDataForView(reqObj.sentData) }
+            );
+
+            $scope.rootBroadcast(constants.YANGMAN_SET_ERROR_DATA,
+                reqObj.receivedData && reqObj.receivedData.hasOwnProperty('errors') ? reqObj.receivedData : {});
+
+            $scope.rootBroadcast(constants.YANGMAN_FILL_NODE_FROM_REQ, { requestUrl: reqObj.path, requestData: data },
+                function (){
+                    $scope.setRightPanelSection(constants.DISPLAY_TYPE_FORM);
+                    $scope.rootBroadcast(constants.YANGMAN_HEADER_INIT, {
+                        path: reqObj.path,
+                        method: reqObj.method,
+                        statusObj: {
+                            status: reqObj.responseStatus,
+                            statusText: reqObj.responseStatusText,
+                            time: reqObj.responseTime,
+                        },
+                    });
+
+                    if ( $scope.node ) {
+                        // prepare data for filling form
+                        data = $scope.node.type === constants.NODE_RPC ?
+                                YangmanService.prepareReceivedData(
+                                    $scope.node,
+                                    reqObj.method,
+                                    reqObj.receivedData,
+                                    reqObj.sentData,
+                                    constants.DISPLAY_TYPE_FORM
+                                ) : data;
+
+                        // try to fill node
+                        YangmanService.fillNodeFromResponse($scope.node, data);
+                        $scope.node.expanded = true;
+                    }
+
+                }
+            );
+
+        }
+
+        /**
+         * Force request header to execute request with data from reqObj
+         * @param reqObj
+         */
+        function executeRequest(reqObj) {
+            showData(reqObj);
+            $scope.rootBroadcast(constants.YANGMAN_EXECUTE_WITH_DATA,{ data: reqObj.sentData });
+        }
+
+        /**
+         * Method for setup data into CM, Header, find api, subapi, node
+         * @param reqObj
+         * @param status
+         */
+        function showData(reqObj, select){
+            var headerObj = {
+                path: reqObj.path,
+                method: reqObj.method,
+            };
+
+            // action select request
+            if ( select ) {
+                headerObj.statusObj = {
+                    status: reqObj.responseStatus,
+                    statusText: reqObj.responseStatusText,
+                    time: reqObj.responseTime,
+                };
+
+                $scope.rootBroadcast(
+                    constants.YANGMAN_SET_ERROR_DATA,
+                    reqObj.receivedData && reqObj.receivedData.hasOwnProperty('errors') ? reqObj.receivedData : {}
+                );
+            }
+
+            $scope.setRightPanelSection(constants.DISPLAY_TYPE_REQ_DATA);
+            $scope.setJsonView(true, reqObj.method !== constants.OPERATION_GET);
+
+            $scope.rootBroadcast(constants.YANGMAN_HEADER_INIT, headerObj);
+            $scope.rootBroadcast(constants.YANGMAN_FILL_NODE_FROM_REQ, { requestUrl: reqObj.path });
+
+            $scope.rootBroadcast(
+                constants.YANGMAN_SET_CODEMIRROR_DATA_RECEIVED,
+                { data: reqObj.setDataForView(reqObj.receivedData) }
+            );
+
+            $scope.rootBroadcast(
+                constants.YANGMAN_SET_CODEMIRROR_DATA_SENT,
+                { data: reqObj.setDataForView(reqObj.sentData) }
+            );
+        }
+
+        /**
+         * Clear current ctrl search value
+         */
+        function clearFilter(){
+            vm.search = '';
+        }
+
+        /**
+         * Dialog for deleting either selected requests or reqObj
+         *
+         * @param event
+         * @param reqObj
+         */
+        function showDgDeleteRequests(event, reqObj){
+
+            var confirm = $mdDialog.confirm()
+                .title($filter('translate')('YANGMAN_DELETE_REQ_CONFIRM_TITLE'))
+                .textContent($filter('translate')('YANGMAN_DELETE_REQ_CONFIRM_TEXT'))
+                .ariaLabel($filter('translate')('YANGMAN_DELETE_REQ_CONFIRM_TITLE'))
+                .targetEvent(event)
+                .ok($filter('translate')('YANGMAN_OK'))
+                .cancel($filter('translate')('YANGMAN_CANCEL'));
+
+            YangmanDesignService.disableMdMenuItem(event);
+
+            $mdDialog.show(confirm).then(function (){
+                if (reqObj){
+                    vm.mainList.deleteRequestItem(reqObj);
+                }
+                else {
+                    vm.mainList.getSelectedItems(
+                        vm.mainList === vm.collectionList ? filterCollReq : filterReq
+                    ).forEach(function (elem){
+                        vm.mainList.deleteRequestItem(elem);
+                    });
+                }
+                vm.mainList.saveToStorage();
+
+                if (vm.mainList === vm.requestList) {
+                    loadHistoryList();
+                }
+                else {
+                    refreshCollectionsWithExpansion();
+                }
+            }, function (){
+                YangmanDesignService.enableMdMenuItem(event);
+            });
+        }
+
+
+        /**
+         * Dialog for deleting collection and refreshing collections
+         * @param ev
+         * @param collObj
+         */
+        function showDgDeleteCollection(ev, collObj){
+            var confirm = $mdDialog.confirm()
+                .title($filter('translate')('YANGMAN_DELETE_COL_CONFIRM_TITLE') + ' ' + collObj.name + '?')
+                .textContent($filter('translate')('YANGMAN_DELETE_COL_CONFIRM_TEXT'))
+                .ariaLabel($filter('translate')('YANGMAN_DELETE_COL_CONFIRM_TITLE'))
+                .targetEvent(ev)
+                .ok($filter('translate')('YANGMAN_OK'))
+                .cancel($filter('translate')('YANGMAN_CANCEL'));
+
+            YangmanDesignService.disableMdMenuItem(ev);
+
+            $mdDialog.show(confirm).then(function (){
+                vm.collectionList.deleteCollection(collObj);
+                vm.collectionList.saveToStorage();
+                refreshCollectionsWithExpansion();
+            }, function (){
+                YangmanDesignService.enableMdMenuItem(ev);
+            });
+        }
+
+        /**
+         * Check if reqObj matches current search value
+         * @param reqObj
+         * @returns {boolean}
+         */
+        function filterReq(reqObj){
+            var searchPhrase = vm.search.toLocaleLowerCase();
+            return reqObj.path.toLowerCase().indexOf(searchPhrase) > -1 ||
+                reqObj.collection.toLowerCase().indexOf(searchPhrase) > -1 ||
+                reqObj.method.toLowerCase() === searchPhrase;
+        }
+
+        /**
+         * Check if collection name matches current search value or any collection req matches
+         * @param colObj
+         */
+        function filterCol(colObj){
+            return filterColName(colObj) || colObj.data.some(filterReq);
+        }
+
+        /**
+         * Get count of requests matching filter in collection colObj
+         * @param colObj
+         * @returns {*}
+         */
+        function colMatchingReqsCount(colObj){
+            return colObj.data.filter(vm.filterReq).length;
+        }
+
+        /**
+         * Check if collection name matches current filter
+         * @param colObj
+         * @returns {boolean}
+         */
+        function filterColName(colObj){
+            return colObj.name.toLowerCase().indexOf(vm.search.toLowerCase()) > -1;
+        }
+
+        /**
+         * Returns true
+         * @returns {boolean}
+         */
+        function fakeFilter(){
+            return true;
+        }
+
+
+        /**
+         * Show dialog for saving reqObj to collection (used for duplicate req too)
+         * @param ev
+         * @param reqObj
+         * @param duplicate
+         */
+        function showDgSaveReq(ev, reqObj, duplicate){
+
+            $mdDialog.show({
+                controller: SaveReqDialogCtrl,
+                controllerAs: 'dialog',
+                templateUrl: $scope.globalViewPath + 'leftpanel/save-req-dialog.tpl.html',
+                parent: angular.element('#yangmanModule'),
+                targetEvent: ev,
+                clickOutsideToClose: true,
+                locals: {
+                    requests: reqObj ? [reqObj] : vm.mainList.getSelectedItems(
+                        vm.mainList === vm.collectionList ? filterCollReq : filterReq
+                    ),
+                    collectionNames: vm.collectionList.getCollectionNames(),
+                    duplicate: duplicate || false,
+                },
+            }).then(saveRequests);
+        }
+
+        /**
+         * Add each request from requests array to collectionList and save
+         * @param requests
+         */
+        function saveRequests(requests){
+            requests.forEach(function (reqObj){
+                vm.collectionList.addItemToList(RequestsService.clearUnnecessaryProperties(reqObj.clone()));
+                vm.collectionList.saveToStorage();
+                refreshCollectionsWithExpansion();
+            });
+        }
+
+
+        /**
+         * Dialog for editing collection name (used for duplicating collection too)
+         * @param ev
+         * @param collection
+         * @param {boolean} duplicate
+         */
+        function showDgEditCollection(ev, collection, duplicate){
+            $mdDialog.show({
+                controller: EditCollectionDialogCtrl,
+                controllerAs: 'dialog',
+                templateUrl: $scope.globalViewPath + 'leftpanel/edit-collection-dialog.tpl.html',
+                parent: angular.element('#yangmanModule'),
+                targetEvent: ev,
+                clickOutsideToClose: true,
+                locals: {
+                    collection: collection,
+                    allCollections: vm.collectionList.collections,
+                    duplicate: duplicate,
+                },
+            }).then(duplicate ? duplicateCollection : changeCollectionName);
+        }
+
+        /**
+         * Rename collection
+         * @param {array} names 0. element is old name, 1. element is new name
+         */
+        function changeCollectionName(names){
+            vm.collectionList.renameCollection(names[0], names[1]);
+            vm.collectionList.saveToStorage();
+            refreshCollectionsWithExpansion();
+        }
+
+        /**
+         * Create collection duplicate, save and refresh collections
+         * @param {array} names 0. element is old name, 1. element is new name
+         */
+        function duplicateCollection(names){
+            vm.collectionList.duplicateCollection(names[0], names[1]);
+            vm.collectionList.saveToStorage();
+            refreshCollectionsWithExpansion();
+        }
+
+
+        function selectNewestRequest() {
+            vm.mainList.toggleReqSelection(true, vm.mainList.getNewestRequest());
+        }
+
+        function loadCollectionsList() {
+            vm.collectionList.loadListFromStorage();
+        }
+
+        function loadHistoryList() {
+            vm.requestList.loadListFromStorage();
+        }
+
+        /**
+         *
+         * @param mainList collectionList or requestList object
+         */
+        function init(mainList){
+
+            vm.collectionList = RequestsService.createEmptyCollectionList('yangman_collectionsList');
+            // collections are loaded for both history and collections tab
+            loadCollectionsList();
+
+            vm.requestList = RequestsService.createEmptyHistoryList('yangman_requestsList');
+
+
+            // if request was selected, deselect requests in all other instances of RequestsListCtrl
+            $scope.$on(constants.YANGMAN_DESELECT_REQUESTS, function (event, params) {
+                if (params.params.broadcastingCtrl !== vm) {
+                    deselectAllRequests();
+                }
+            });
+
+            $scope.$on(constants.YANGMAN_REFRESH_COLLECTIONS, function (event, params){
+                loadCollectionsList();
+                (params.cbk || angular.noop)();
+            });
+
+            // list type dependend operations
+            if (mainList === 'history') {
+
+                vm.mainList = vm.requestList;
+                loadHistoryList();
+
+                $scope.$on(constants.YANGMAN_REFRESH_HISTORY, loadHistoryList);
+                // saving from request header after execution
+                $scope.$on(constants.YANGMAN_SAVE_EXECUTED_REQUEST, saveBcstedHistoryRequest);
+                // select newest request
+                $scope.$on(constants.YANGMAN_SELECT_THE_NEWEST_REQUEST, selectNewestRequest);
+            }
+            else {
+                vm.mainList = vm.collectionList;
+                // saving from request header
+                $scope.$on(constants.YANGMAN_SAVE_REQUEST_TO_COLLECTION, saveRequestFromExt);
+                // saving collections expanded status on refresh
+                $scope.$on(constants.YANGMAN_REFRESH_AND_EXPAND_COLLECTIONS, function(){
+                    var expandedColNames = vm.collectionList.getExpandedCollectionNames();
+                    $scope.rootBroadcast(constants.YANGMAN_REFRESH_COLLECTIONS, {}, function (){
+                        vm.collectionList.expandCollectionByNames(expandedColNames);
+                    });
+                });
+            }
+
+        }
+
+
+        /**
+         * Request in list selection
+         * For history reqs it is possible multiselect, thats why event.ctrlKey is used
+         * @param event
+         * @param requestObj
+         */
+        function selectRequest(event, requestObj){
+            $scope.rootBroadcast(constants.YANGMAN_DESELECT_REQUESTS, { broadcastingCtrl: vm });
+            vm.mainList.toggleReqSelection(!event.ctrlKey, requestObj);
+            if (!event.ctrlKey){
+                if ($scope.rightPanelSection === constants.DISPLAY_TYPE_FORM) {
+                    vm.showForm(requestObj, true);
+                }
+                else {
+                    vm.showData(requestObj, true);
+                }
+            }
+        }
+
+        /**
+         * Mark only requestObj in current list as selected
+         * Used for example when user clicks on request submenu
+         * @param requestObj
+         */
+        function selectOnlyThisRequest(requestObj){
+            vm.mainList.toggleReqSelection(true, requestObj);
+        }
+
+        /**
+         * Deselect history requests
+         */
+        function deselectAllFilteredReqs(){
+            vm.mainList.deselectAllFilteredItems(vm.mainList === vm.collectionList ? filterCollReq : vm.filterReq);
+        }
+
+        function deselectAllRequests() {
+            vm.mainList.deselectAllItems();
+        }
+
+        /**
+         * Select history requests
+         */
+        function selectAllFilteredReqs(){
+            vm.mainList.selectAllFilteredItems(vm.mainList === vm.collectionList ? filterCollReq : vm.filterReq);
+        }
+
+        /**
+         * Use when selecting filtered requests if they are saved to some collection
+         * Additional filter is if the collection of the request is expanded
+         * @param request
+         * @returns {*|boolean}
+         */
+        function filterCollReq(request) {
+            return vm.collectionList.getCollection(request.collection).expanded && vm.filterReq(request);
+        }
+
+        /**
+         * Refresh and expand collections
+         */
+        function refreshCollectionsWithExpansion(){
+            $scope.rootBroadcast(constants.YANGMAN_REFRESH_AND_EXPAND_COLLECTIONS);
+        }
+
+    }
+
+});
diff --git a/modules/yangman-resources/src/main/resources/yangman/controllers/save-req-dialog.controller.js b/modules/yangman-resources/src/main/resources/yangman/controllers/save-req-dialog.controller.js
new file mode 100644 (file)
index 0000000..0230a73
--- /dev/null
@@ -0,0 +1,47 @@
+define([], function () {
+    'use strict';
+
+    angular.module('app.yangman').controller('SaveReqDialogCtrl', SaveReqDialogCtrl);
+
+    SaveReqDialogCtrl.$inject = ['$filter', '$mdDialog', 'collectionNames', 'requests', 'duplicate'];
+
+    function SaveReqDialogCtrl($filter, $mdDialog, collectionNames, requests, duplicate) {
+        var vm = this;
+
+        vm.collectionNames = collectionNames;
+        vm.collectionName = duplicate ? requests[0].collection : '';
+        vm.getColAutocomplete   = getColAutocomplete;
+        vm.requests = requests;
+        vm.duplicate = duplicate;
+
+        vm.cancel = cancel;
+        vm.save = save;
+
+        cloneRequests();
+
+        function getColAutocomplete() {
+            return vm.collectionNames ? $filter('filter')(vm.collectionNames, vm.collectionName) : vm.collectionNames;
+        }
+
+        function cloneRequests(){
+            vm.requests = vm.requests.map(function (req){
+                return req.clone();
+            });
+        }
+
+        function cancel() {
+            $mdDialog.cancel();
+        }
+
+        function save() {
+            vm.requests.forEach(function (reqObj){
+                reqObj.collection = vm.collectionName;
+            });
+            $mdDialog.hide(vm.requests);
+        }
+
+    }
+
+    return SaveReqDialogCtrl;
+
+});
diff --git a/modules/yangman-resources/src/main/resources/yangman/controllers/yang-form.controller.js b/modules/yangman-resources/src/main/resources/yangman/controllers/yang-form.controller.js
new file mode 100644 (file)
index 0000000..f312608
--- /dev/null
@@ -0,0 +1,79 @@
+define([
+    'app/yangman/controllers/form/ym-augmentation-modal.controller',
+    'app/yangman/controllers/form/ym-case.controller',
+    'app/yangman/controllers/form/ym-container.controller',
+    'app/yangman/controllers/form/ym-choice.controller',
+    'app/yangman/controllers/form/ym-input.controller',
+    'app/yangman/controllers/form/ym-leaf.controller',
+    'app/yangman/controllers/form/ym-leaf-list.controller',
+    'app/yangman/controllers/form/ym-list.controller',
+    'app/yangman/controllers/form/ym-output.controller',
+    'app/yangman/controllers/form/ym-rpc.controller',
+    'app/yangman/controllers/form/ym-type.controller',
+    'app/yangman/controllers/form/ym-type-bit.controller',
+    'app/yangman/controllers/form/ym-type-boolean.controller',
+    'app/yangman/controllers/form/ym-type-empty.controller',
+    'app/yangman/controllers/form/ym-type-enum.controller',
+    'app/yangman/directives/yang-form-menu.directive',
+    'app/yangman/directives/ym-info-box.directive',
+], function () {
+    'use strict';
+
+    angular.module('app.yangman').controller('YangFormCtrl', YangFormCtrl);
+
+    YangFormCtrl.$inject = ['$scope', '$rootScope', '$filter', 'constants', 'YangUtilsService'];
+
+    function YangFormCtrl($scope, $rootScope, $filter, constants) {
+        var yangForm = this;
+
+        yangForm.viewPath = $scope.globalViewPath + 'rightpanel/form';
+        yangForm.errorMsg = '';
+        $scope.constants = constants;
+
+        // methods
+        yangForm.getNodeName = getNodeName;
+
+        // watchers
+        $scope.$on(constants.YANGMAN_SET_ERROR_DATA, setRcvdErrorData);
+
+        $scope.$on(constants.YANGMAN_SET_ERROR_MESSAGE, setErrorMessage);
+
+        /**
+         * Method for set error message in form
+         * @param event
+         * @param message
+         */
+        function setErrorMessage(event, data){
+            yangForm.errorMsg = data.params;
+        }
+
+        /**
+         * Read and set error message received from header controller
+         * @param event
+         * @param data
+         */
+        function setRcvdErrorData(event, data) {
+
+            if (data.params.errors) {
+                yangForm.errorMsg = data.params.errors.error[0]['error-message'];
+            }
+            else {
+                yangForm.errorMsg = '';
+            }
+        }
+
+        /**
+         * Get node label name
+         * @param localeLabel
+         * @param label
+         * @returns {*}
+         */
+        function getNodeName(localeLabel, label) {
+            var localeResult = $filter('translate')(localeLabel);
+            return localeResult.indexOf(constants.LOCALE_PREFIX) === 0 ? label : localeResult;
+        }
+
+
+    }
+
+});
diff --git a/modules/yangman-resources/src/main/resources/yangman/controllers/yangman.controller.js b/modules/yangman-resources/src/main/resources/yangman/controllers/yangman.controller.js
new file mode 100644 (file)
index 0000000..907b6e3
--- /dev/null
@@ -0,0 +1,375 @@
+define([
+    'app/yangman/yangman.filters',
+    'app/yangman/controllers/modules-list.controller',
+    'app/yangman/controllers/module-detail.controller',
+    'app/yangman/controllers/yang-form.controller',
+    'app/yangman/controllers/requests-list.controller',
+    'app/yangman/controllers/request-header.controller',
+    'app/yangman/controllers/request-data.controller',
+    'app/yangman/services/yangman.services',
+    'app/yangman/services/handle-file.services',
+    'app/yangman/services/yangman-design.services',
+    'app/yangman/services/requests.services',
+    'app/yangman/services/parameters.services',
+    'app/yangman/services/plugins-unsetter.services',
+    'app/yangman/directives/ui-codemirror.directive',
+    'app/yangman/directives/read_file.directive',
+], function () {
+    'use strict';
+
+    angular.module('app.yangman').controller('YangmanCtrl', YangmanCtrl);
+
+    YangmanCtrl.$inject = [
+        '$mdDialog', '$scope', '$rootScope', 'YangmanDesignService', 'RequestBuilderService',
+        'EventDispatcherService', 'constants', 'ParametersService', 'PathUtilsService', 'PluginsUnsetterService', '$timeout',
+    ];
+
+    function YangmanCtrl(
+        $mdDialog, $scope, $rootScope, YangmanDesignService, RequestBuilderService,
+        EventDispatcherService, constants, ParametersService, PathUtilsService, PluginsUnsetterService, $timeout
+    ) {
+        var main = this;
+
+        $rootScope.section_logo = 'assets/images/logo_yangman.png';
+        $scope.globalViewPath = 'src/app/yangman/views/';
+
+        $scope.selectedModule = null;
+        $scope.selectedDatastore = null;
+        $scope.apis = [];
+        $scope.node = null;
+        $scope.rightPanelSection = constants.DISPLAY_TYPE_REQ_DATA;
+        $scope.augmentations = {};
+        $scope.selectedApi = null;
+        $scope.selectedSubApi = null;
+        $scope.historyReqsSelected = false;
+        $scope.requestToShow = null;
+        $scope.requestDataToShow = '';
+        $scope.parametersList = ParametersService.createEmptyParametersList('yangman_parameters');
+        $scope.shownCMHint = false;
+
+        main.selectedMainTab = 0;
+        main.leftPanelTab = 0;
+        main.jsonView = {
+            received: true,
+            sent: false,
+        };
+        main.executingRequestProgress = false;
+        main.constants = constants;
+
+        // methods
+        main.init = init;
+        main.initModuleDetailHeight = initModuleDetailHeight;
+        main.switchedTab = switchedTab;
+        main.toggleLeftPanel = toggleLeftPanel;
+        main.leftPanelShowModule = leftPanelShowModule;
+        main.modulesTreeDisplayed = modulesTreeDisplayed;
+
+        // scope global methods
+        $scope.buildRootRequest = buildRootRequest;
+        $scope.broadcastFromRoot = broadcastFromRoot;
+        $scope.checkAddingListElement = checkAddingListElement;
+        $scope.clearCM = clearCM;
+        $scope.rootBroadcast = rootBroadcast;
+        $scope.setApi = setApi;
+        $scope.setDataStore = setDataStore;
+        $scope.setGlobalParams = setGlobalParams;
+        $scope.setJsonView = setJsonView;
+        $scope.setLeftPanel = setLeftPanel;
+        $scope.setModule = setModule;
+        $scope.setNode = setNode;
+        $scope.setRequestToShow = setRequestToShow;
+        $scope.setRightPanelSection = setRightPanelSection;
+        $scope.switchSection = switchSection;
+        $scope.setParametersList = setParametersList;
+        $scope.unsetPlugin = unsetPlugin;
+        $scope.setCMHintShown = setCMHintShown;
+
+        init();
+
+        function setCMHintShown(shown) {
+            $scope.shownCMHint = shown;
+        }
+
+        function startExecutingRequestProgress() {
+            main.executingRequestProgress = true;
+        }
+
+        function stopExecutingRequestProgress() {
+            main.executingRequestProgress = false;
+        }
+
+        /**
+         * Set parametersList
+         * @param parametersList
+         */
+        function setParametersList(parametersList) {
+            $scope.parametersList = parametersList;
+        }
+
+
+        /**
+         * Broadcast from this main controller to all children ctrls
+         * @param eventName
+         * @param val
+         */
+        function broadcastFromRoot(eventName, val) {
+            $scope.$broadcast(eventName, val);
+        }
+        /**
+         * Initialization
+         */
+        function init(){
+            $scope.$on(constants.YANGMAN_EXECUTING_REQUEST_PROGRESS_START, startExecutingRequestProgress);
+            $scope.$on(constants.YANGMAN_EXECUTING_REQUEST_PROGRESS_STOP, stopExecutingRequestProgress);
+
+            YangmanDesignService.hideMainMenu();
+            YangmanDesignService.setDraggableLeftPanel();
+            YangmanDesignService.setJsonSplitter(forceCMsRefresh);
+
+            EventDispatcherService.registerHandler(constants.EV_FILL_PATH, fillPathIdentifiersByKey);
+            EventDispatcherService.registerHandler(constants.EV_LIST_CHANGED, fillPathIdentifiersByListData);
+        }
+
+        /**
+         * Initialize module detail height, with timeout
+         */
+        function initModuleDetailHeight(){
+            $timeout(function () {
+                YangmanDesignService.setModuleDetailHeight();
+            }, 1500);
+        }
+
+        /**
+         * Method for fill key into request path
+         * @param inputs
+         */
+        function fillPathIdentifiersByKey(inputs) {
+            var node = inputs[0],
+                value = inputs[1] || '';
+
+            if ($scope.selectedSubApi && node.parent && $scope.selectedSubApi.node.id === node.parent.id) {
+                var identifiers =
+                    $scope.selectedSubApi.pathArray[$scope.selectedSubApi.pathArray.length - 1].identifiers;
+
+                PathUtilsService.fillIdentifiers(identifiers, node.label, value);
+            }
+        }
+
+        // TODO :: description
+        function fillPathIdentifiersByListData(inputs) {
+            var node = inputs[0];
+
+            if ($scope.selectedSubApi && node && $scope.selectedSubApi.node.id === node.id) {
+                var identifiers =
+                        $scope.selectedSubApi.pathArray[$scope.selectedSubApi.pathArray.length - 1].identifiers,
+                    keys = node.refKey;
+
+                keys.forEach(function (key) {
+                    PathUtilsService.fillIdentifiers(identifiers, key.label, key.value);
+                });
+            }
+        }
+
+        // TODO :: description
+        function modulesTreeDisplayed() {
+            return main.selectedMainTab === 0;
+        }
+
+        /**
+         * Set switched tab index
+         */
+        function switchedTab(index){
+            main.selectedMainTab = index;
+        }
+
+        /**
+         * Switcher between modules list and module detail
+         */
+        function toggleLeftPanel(){
+            main.leftPanelTab = (main.leftPanelTab + 1) % 2;
+        }
+
+        /**
+         * Method for opening model detail tab
+         */
+        function leftPanelShowModule() {
+            if ($scope.node) {
+                main.leftPanelTab = 1;
+            }
+        }
+
+        /**
+         * General method for switching different section in application
+         * @param param
+         * @param section
+         */
+        function switchSection(param, section){
+            $scope[param] = section;
+        }
+
+        /**
+         * Genereal method for clearing code mirror - sent and received data too
+         */
+        function clearCM(){
+            $scope.rootBroadcast(constants.YANGMAN_SET_CODEMIRROR_DATA_RECEIVED, { data: JSON.stringify({}) });
+            $scope.rootBroadcast(constants.YANGMAN_SET_CODEMIRROR_DATA_SENT, { data: JSON.stringify({}) });
+        }
+
+
+        // SETTERS
+
+        /**
+         * Switcher for module detail and module list
+         * @param value
+         */
+        function setLeftPanel(value) {
+            if ( !angular.isUndefined(value) ) {
+                main.leftPanelTab = value;
+            }
+        }
+
+        /**
+         * Set global necessary params
+         * @param apis
+         */
+        function setGlobalParams(apis, augmentations){
+            $scope.apis = apis;
+            $scope.augmentations = augmentations;
+        }
+
+        /**
+         * Set node to global param
+         * @param node
+         */
+        function setNode(node){
+            $scope.node = node;
+
+            if ( $scope.node ) {
+                $scope.node.clear();
+                $scope.$broadcast(constants.YANGMAN_DISABLE_ADDING_LIST_ELEMENT);
+            }
+        }
+
+        /**
+         * Set module to global param
+         * @param module
+         */
+        function setModule(module){
+            $scope.selectedModule = module;
+        }
+
+        /**
+         * Set dataStore to global param && open module detail in left panel
+         * @param dataStore
+         * @param expand
+         */
+        function setDataStore(dataStore, expand, leftPanel){
+            $scope.selectedDatastore = dataStore;
+
+            if ( expand ) {
+                $scope.node = null;
+                setLeftPanel(leftPanel);
+                $scope.$broadcast(constants.YANGMAN_MODULE_D_INIT);
+            } else {
+
+                if ( $scope.node ) {
+                    $scope.node.clear();
+                }
+            }
+        }
+
+        /**
+         * Build request json from root node
+         */
+        function buildRootRequest() {
+            var obj = {};
+            $scope.node.buildRequest(RequestBuilderService, obj, $scope.node.module);
+            return obj;
+        }
+
+        /**
+         * Set api and sub api to global param
+         * @param api
+         * @param subApi
+         */
+        function setApi(api, subApi, setUrl, clearPathArray){
+            $scope.selectedApi = api;
+            $scope.selectedSubApi = subApi;
+
+            if ( clearPathArray ){
+                PathUtilsService.clearPath($scope.selectedSubApi.pathArray);
+            }
+
+            $scope.$broadcast(constants.SET_SEL_OPERATIONS, subApi ? $scope.selectedSubApi.operations : [], setUrl);
+        }
+
+        /**
+         * Call broadcast from root to child controllers
+         * @param broadcast
+         * @param params
+         * @param cbk
+         */
+        function rootBroadcast(broadcast, params, cbk){
+            $scope.$broadcast(broadcast, { params: params, cbk: cbk });
+        }
+
+        /**
+         * Set request from history or collections to show data in code mirror
+         * @param reqObj
+         * @param {'sentData'|'receivedData'} dataType
+         */
+        function setRequestToShow(reqObj, dataType) {
+            $scope.requestToShow = reqObj;
+            $scope.requestDataToShow = dataType;
+        }
+
+        /**
+         * Set rightPanelSection to display current section in right panel
+         * @param section 'form', 'req-data'
+         */
+        function setRightPanelSection(section) {
+            $scope.rightPanelSection = section;
+        }
+
+        /**
+         * Which codemirror instances will be displayed
+         * @param received
+         * @param sent
+         */
+        function setJsonView(received, sent){
+            main.jsonView.received = received;
+            main.jsonView.sent = sent;
+            forceCMsRefresh();
+            YangmanDesignService.setJsonSplitter(forceCMsRefresh);
+        }
+
+        /**
+         * Force refresh of all codemirror instances
+         */
+        function forceCMsRefresh(){
+            var elems = angular.element(document).find('.CodeMirror');
+            for (var i = 0; i < elems.length; i++){
+                var cmInstance = elems[i].CodeMirror;
+                cmInstance._handlers.changes[0](cmInstance);
+            }
+        }
+
+        /**
+         * Global method for unset plugin
+         * @param selectedPlugin
+         * @param controller
+         */
+        function unsetPlugin(controller){
+            PluginsUnsetterService.unset($scope, controller);
+        }
+
+        /**
+         * Checks if the element list should be disabled
+         */
+        function checkAddingListElement(node) {
+            return $scope.node === node && $scope.node.type === 'list' &&
+                $scope.node.refKey && $scope.node.refKey.length;
+        }
+    }
+
+});
diff --git a/modules/yangman-resources/src/main/resources/yangman/directives/abn-tree.directive.js b/modules/yangman-resources/src/main/resources/yangman/directives/abn-tree.directive.js
new file mode 100644 (file)
index 0000000..0635853
--- /dev/null
@@ -0,0 +1,585 @@
+define(['angular'], function (angular) {
+    'use strict';
+
+    angular.module('app.yangman').directive('abnApiTree', [
+        '$timeout', 'constants', function ($timeout, constants) {
+            return {
+                restrict: 'E',
+                templateUrl: 'src/app/yangman/views/directives/abn-tree.tpl.html',
+                replace: true,
+                scope: {
+                    treeData: '=',
+                    onSelect: '&',
+                    initialSelection: '@',
+                    treeControl: '=',
+                    treeRows: '=',
+                },
+                link: function (scope, element, attrs) {
+                    var expandAllParents,
+                        expandLevel,
+                        forAllAncestors,
+                        forEachBranch,
+                        getParent,
+                        n,
+                        onTreeDataChange,
+                        selectBranch,
+                        selectedBranch,
+                        tree;
+
+                    if (attrs.iconExpand == null) {
+                        attrs.iconExpand = constants.ICON_EXPAND_ADD;
+                    }
+                    if (attrs.iconCollapse == null) {
+                        attrs.iconCollapse = constants.ICON_COLLAPSE_REMOVE;
+                    }
+                    if (attrs.iconLeaf == null) {
+                        attrs.iconLeaf = constants.ICON_KEYBOARD_ARROW_RIGHT;
+                    }
+                    if (attrs.expandLevel == null) {
+                        attrs.expandLevel = constants.EXPAND_LEVEL_THREE;
+                    }
+                    expandLevel = parseInt(attrs.expandLevel, 10);
+                    if (!scope.treeData) {
+                        return;
+                    }
+                    if (scope.treeData.length == null) {
+                        if (scope.treeData.label != null) {
+                            scope.treeData = [scope.treeData];
+                        } else {
+                            return;
+                        }
+                    }
+                    forEachBranch = function (f) {
+                        var do_f,
+                            root_branch,
+                            _i,
+                            _len,
+                            _ref,
+                            _results;
+
+                        do_f = function (branch, level) {
+                            var child,
+                                _i,
+                                _len,
+                                _ref,
+                                _results;
+
+                            f(branch, level);
+                            if (branch.children != null) {
+                                _ref = branch.children;
+                                _results = [];
+                                for (_i = 0, _len = _ref.length; _i < _len; _i++) {
+                                    child = _ref[_i];
+                                    _results.push(do_f(child, level + 1));
+                                }
+                                return _results;
+                            }
+                        };
+                        _ref = scope.treeData;
+                        _results = [];
+                        for (_i = 0, _len = _ref.length; _i < _len; _i++) {
+                            root_branch = _ref[_i];
+                            _results.push(do_f(root_branch, 1));
+                        }
+                        return _results;
+                    };
+                    selectedBranch = null;
+                    selectBranch = function (branch) {
+                        if (!branch) {
+                            if (selectedBranch != null) {
+                                selectedBranch.selected = false;
+                            }
+                            selectedBranch = null;
+                            return;
+                        }
+
+                        if (selectedBranch != null) {
+                            selectedBranch.selected = false;
+                        }
+                        branch.selected = true;
+                        selectedBranch = branch;
+                        expandAllParents(branch);
+                        if (branch.onSelect != null) {
+                            return $timeout(function () {
+                                return branch.onSelect(branch);
+                            });
+                        } else {
+                            if (scope.onSelect != null) {
+                                return $timeout(function () {
+                                    return scope.onSelect({
+                                        branch: branch,
+                                    });
+                                });
+                            }
+                        }
+
+                    };
+                    scope.user_clicks_branch = function (branch) {
+
+                        scope.tree_rows.forEach(function (item){
+                            item.branch.selected = false;
+                        });
+
+                        if (branch === selectedBranch) {
+                            branch.selected = true;
+                        }
+
+                        return selectBranch(branch);
+                    };
+
+                    getParent = function (child) {
+                        var parent;
+                        parent = void 0;
+                        if (child.parent_uid) {
+                            forEachBranch(function (b) {
+                                if (b.uid === child.parent_uid) {
+                                    return parent = b;
+                                }
+                            });
+                        }
+                        return parent;
+                    };
+                    forAllAncestors = function (child, fn) {
+                        var parent;
+                        parent = getParent(child);
+                        if (parent != null) {
+                            fn(parent);
+                            return forAllAncestors(parent, fn);
+                        }
+                    };
+                    expandAllParents = function (child) {
+                        return forAllAncestors(child, function (b) {
+                            return b.expanded = true;
+                        });
+                    };
+
+                    scope.expandedTree = false;
+                    scope.expand_collapse_all_items = function (){
+
+                        var expand = !scope.expandedTree ? true : false;
+
+                        scope.tree_rows.forEach(function (child){
+                            child.branch.expanded = expand;
+                        });
+
+                        scope.expandedTree = !scope.expandedTree;
+                    };
+                    scope.collapse_others = function (){
+                        var parentId = null,
+                            expandParent = function (parentId){
+                                if ( parentId ) {
+                                    scope.tree_rows.forEach(function (child){
+                                        if ( child.branch.uid === parentId ) {
+                                            child.branch.expanded = true;
+                                            parentId = child.branch.parent_uid;
+
+                                            if ( parentId ) {
+                                                expandParent(parentId);
+                                            }
+                                        }
+                                    });
+                                }
+                            };
+
+                        scope.tree_rows.forEach(function (child){
+                            if ( child.branch.selected ) {
+                                parentId = child.branch.parent_uid;
+                            }
+                            child.branch.expanded = child.branch.selected ? child.branch.expanded : false;
+                        });
+
+                        if ( parentId ) {
+                            expandParent(parentId);
+                        }
+
+                    };
+
+                    scope.$watch(constants.TREE_ROWS, function () {
+                        scope.treeRows = scope.tree_rows;
+                        scope.$emit(constants.SET_SCOPE_TREE_ROWS, scope.treeRows);
+                    });
+
+                    scope.tree_rows = [];
+                    onTreeDataChange = function () {
+                        var add_branch_to_list,
+                            root_branch,
+                            _i,
+                            _len,
+                            _ref,
+                            _results;
+
+                        forEachBranch(function (b) {
+                            if (!b.uid) {
+                                return b.uid = '' + Math.random();
+                            }
+                        });
+                        forEachBranch(function (b) {
+                            var child,
+                                _i,
+                                _len,
+                                _ref,
+                                _results;
+
+                            if (angular.isArray(b.children)) {
+                                _ref = b.children;
+                                _results = [];
+                                for (_i = 0, _len = _ref.length; _i < _len; _i++) {
+                                    child = _ref[_i];
+                                    _results.push(child.parent_uid = b.uid);
+                                }
+                                return _results;
+                            }
+                        });
+                        scope.tree_rows = [];
+                        forEachBranch(function (branch) {
+                            var child,
+                                f;
+
+                            if (branch.children) {
+                                if (branch.children.length > 0) {
+                                    f = function (e) {
+                                        if (typeof e === 'string') {
+                                            return {
+                                                label: e,
+                                                children: [],
+                                            };
+                                        } else {
+                                            return e;
+                                        }
+                                    };
+                                    return branch.children = (function () {
+                                        var _i,
+                                            _len,
+                                            _ref,
+                                            _results;
+
+                                        _ref = branch.children;
+                                        _results = [];
+                                        for (_i = 0, _len = _ref.length; _i < _len; _i++) {
+                                            child = _ref[_i];
+                                            _results.push(f(child));
+                                        }
+                                        return _results;
+                                    })();
+                                }
+                            } else {
+                                return branch.children = [];
+                            }
+                        });
+                        add_branch_to_list = function (level, branch, visible) {
+                            var child,
+                                child_visible,
+                                tree_icon,
+                                _i,
+                                _len,
+                                _ref,
+                                _results;
+
+                            if (branch.expanded == null) {
+                                branch.expanded = false;
+                            }
+                            if (!branch.children || branch.children.length === 0) {
+                                tree_icon = attrs.iconLeaf;
+                            } else {
+                                if (branch.expanded) {
+                                    tree_icon = attrs.iconCollapse;
+                                } else {
+                                    tree_icon = attrs.iconExpand;
+                                }
+                            }
+                            scope.tree_rows.push({
+                                level: level,
+                                branch: branch,
+                                label: branch.label,
+                                tree_icon: tree_icon,
+                                visible: visible,
+                            });
+                            if (branch.children != null) {
+                                _ref = branch.children;
+                                _results = [];
+                                for (_i = 0, _len = _ref.length; _i < _len; _i++) {
+                                    child = _ref[_i];
+                                    child_visible = visible && branch.expanded;
+                                    _results.push(add_branch_to_list(level + 1, child, child_visible));
+                                }
+                                return _results;
+                            }
+                        };
+                        _ref = scope.treeData;
+                        _results = [];
+                        for (_i = 0, _len = _ref.length; _i < _len; _i++) {
+                            root_branch = _ref[_i];
+                            _results.push(add_branch_to_list(1, root_branch, true));
+                        }
+                        return _results;
+                    };
+                    scope.$watch('treeData', onTreeDataChange, true);
+                    if (attrs.initialSelection != null) {
+                        forEachBranch(function (b) {
+                            if (b.label === attrs.initialSelection) {
+                                return $timeout(function () {
+                                    return selectBranch(b);
+                                });
+                            }
+                        });
+                    }
+                    n = scope.treeData.length;
+                    forEachBranch(function (b, level) {
+                        b.level = level;
+                        return b.expanded = b.level < expandLevel;
+                    });
+                    if (scope.treeControl != null) {
+                        if (angular.isObject(scope.treeControl)) {
+                            tree = scope.treeControl;
+                            tree.expand_all = function () {
+                                return forEachBranch(function (b) {
+                                    return b.expanded = true;
+                                });
+                            };
+                            tree.collapse_all = function () {
+                                return forEachBranch(function (b) {
+                                    return b.expanded = false;
+                                });
+                            };
+                            tree.get_first_branch = function () {
+                                n = scope.treeData.length;
+                                if (n > 0) {
+                                    return scope.treeData[0];
+                                }
+                            };
+                            tree.select_first_branch = function () {
+                                var b;
+                                b = tree.get_first_branch();
+                                return tree.selectBranch(b);
+                            };
+                            tree.get_selected_branch = function () {
+                                return selectedBranch;
+                            };
+                            tree.get_parent_branch = function (b) {
+                                return getParent(b);
+                            };
+                            tree.select_branch = function (b) {
+                                selectBranch(b);
+                                return b;
+                            };
+                            tree.get_children = function (b) {
+                                return b.children;
+                            };
+                            tree.select_parent_branch = function (b) {
+                                var p;
+                                if (b == null) {
+                                    b = tree.get_selected_branch();
+                                }
+                                if (b != null) {
+                                    p = tree.get_parent_branch(b);
+                                    if (p != null) {
+                                        tree.select_branch(p);
+                                        return p;
+                                    }
+                                }
+                            };
+                            tree.add_branch = function (parent, new_branch) {
+                                if (parent != null) {
+                                    parent.children.push(new_branch);
+                                    parent.expanded = true;
+                                } else {
+                                    scope.treeData.push(new_branch);
+                                }
+                                return new_branch;
+                            };
+                            tree.add_root_branch = function (new_branch) {
+                                tree.add_branch(null, new_branch);
+                                return new_branch;
+                            };
+                            tree.expand_branch = function (b) {
+                                if (b == null) {
+                                    b = tree.get_selected_branch();
+                                }
+                                if (b != null) {
+                                    b.expanded = true;
+                                    return b;
+                                }
+                            };
+                            tree.collapse_branch = function (b) {
+                                if (b == null) {
+                                    b = selectedBranch;
+                                }
+                                if (b != null) {
+                                    b.expanded = false;
+                                    return b;
+                                }
+                            };
+                            tree.get_siblings = function (b) {
+                                var p,
+                                    siblings;
+
+                                if (b == null) {
+                                    b = selectedBranch;
+                                }
+                                if (b != null) {
+                                    p = tree.get_parent_branch(b);
+                                    if (p) {
+                                        siblings = p.children;
+                                    } else {
+                                        siblings = scope.treeData;
+                                    }
+                                    return siblings;
+                                }
+                            };
+                            tree.get_next_sibling = function (b) {
+                                var i,
+                                    siblings;
+
+                                if (b == null) {
+                                    b = selectedBranch;
+                                }
+                                if (b != null) {
+                                    siblings = tree.get_siblings(b);
+                                    n = siblings.length;
+                                    i = siblings.indexOf(b);
+                                    if (i < n) {
+                                        return siblings[i + 1];
+                                    }
+                                }
+                            };
+                            tree.get_prev_sibling = function (b) {
+                                var i,
+                                    siblings;
+
+                                if (b == null) {
+                                    b = selectedBranch;
+                                }
+                                siblings = tree.get_siblings(b);
+                                n = siblings.length;
+                                i = siblings.indexOf(b);
+                                if (i > 0) {
+                                    return siblings[i - 1];
+                                }
+                            };
+                            tree.select_next_sibling = function (b) {
+                                var next;
+                                if (b == null) {
+                                    b = selectedBranch;
+                                }
+                                if (b != null) {
+                                    next = tree.get_next_sibling(b);
+                                    if (next != null) {
+                                        return tree.select_branch(next);
+                                    }
+                                }
+                            };
+                            tree.select_prev_sibling = function (b) {
+                                var prev;
+                                if (b == null) {
+                                    b = selectedBranch;
+                                }
+                                if (b != null) {
+                                    prev = tree.get_prev_sibling(b);
+                                    if (prev != null) {
+                                        return tree.select_branch(prev);
+                                    }
+                                }
+                            };
+                            tree.get_first_child = function (b) {
+                                var _ref;
+                                if (b == null) {
+                                    b = selectedBranch;
+                                }
+                                if (b != null) {
+                                    if (((_ref = b.children) != null ? _ref.length : void 0) > 0) {
+                                        return b.children[0];
+                                    }
+                                }
+                            };
+                            tree.get_closest_ancestor_next_sibling = function (b) {
+                                var next,
+                                    parent;
+
+                                next = tree.get_next_sibling(b);
+                                if (next != null) {
+                                    return next;
+                                } else {
+                                    parent = tree.get_parent_branch(b);
+                                    return tree.get_closest_ancestor_next_sibling(parent);
+                                }
+                            };
+                            tree.get_next_branch = function (b) {
+                                var next;
+                                if (b == null) {
+                                    b = selectedBranch;
+                                }
+                                if (b != null) {
+                                    next = tree.get_first_child(b);
+                                    if (next != null) {
+                                        return next;
+                                    } else {
+                                        next = tree.get_closest_ancestor_next_sibling(b);
+                                        return next;
+                                    }
+                                }
+                            };
+                            tree.select_next_branch = function (b) {
+                                var next;
+                                if (b == null) {
+                                    b = selectedBranch;
+                                }
+                                if (b != null) {
+                                    next = tree.get_next_branch(b);
+                                    if (next != null) {
+                                        tree.select_branch(next);
+                                        return next;
+                                    }
+                                }
+                            };
+                            tree.last_descendant = function (b) {
+                                var last_child;
+                                if (b == null) {
+                                    // debugger;
+                                }
+                                n = b.children.length;
+                                if (n === 0) {
+                                    return b;
+                                } else {
+                                    last_child = b.children[n - 1];
+                                    return tree.last_descendant(last_child);
+                                }
+                            };
+                            tree.get_prev_branch = function (b) {
+                                var parent,
+                                    prev_sibling;
+
+                                if (b == null) {
+                                    b = selectedBranch;
+                                }
+                                if (b != null) {
+                                    prev_sibling = tree.get_prev_sibling(b);
+                                    if (prev_sibling != null) {
+                                        return tree.last_descendant(prev_sibling);
+                                    } else {
+                                        parent = tree.get_parent_branch(b);
+                                        return parent;
+                                    }
+                                }
+                            };
+                            return tree.select_prev_branch = function (b) {
+                                var prev;
+                                if (b == null) {
+                                    b = selectedBranch;
+                                }
+                                if (b != null) {
+                                    prev = tree.get_prev_branch(b);
+                                    if (prev != null) {
+                                        tree.select_branch(prev);
+                                        return prev;
+                                    }
+                                }
+                            };
+                        }
+                    }
+                },
+            };
+        },
+    ]);
+
+
+});
diff --git a/modules/yangman-resources/src/main/resources/yangman/directives/read_file.directive.js b/modules/yangman-resources/src/main/resources/yangman/directives/read_file.directive.js
new file mode 100644 (file)
index 0000000..c5a8fa3
--- /dev/null
@@ -0,0 +1,29 @@
+define([], function () {
+    'use strict';
+
+    angular.module('app.yangman').directive('onReadFile', readFileDirective);
+
+    readFileDirective.$inject = ['$parse'];
+
+    function readFileDirective($parse) {
+        return {
+            restrict: 'A',
+            scope: false,
+            link: function (scope, element, attrs) {
+                var fn = $parse(attrs.onReadFile);
+
+                element.on('change', function (onChangeEvent) {
+                    var reader = new FileReader();
+
+                    reader.onload = function (onLoadEvent) {
+                        scope.$apply(function () {
+                            fn(scope, { $fileContent: onLoadEvent.target.result });
+                        });
+                    };
+
+                    reader.readAsText((onChangeEvent.srcElement || onChangeEvent.target).files[0]);
+                });
+            },
+        };
+    }
+});
diff --git a/modules/yangman-resources/src/main/resources/yangman/directives/ui-codemirror.directive.js b/modules/yangman-resources/src/main/resources/yangman/directives/ui-codemirror.directive.js
new file mode 100644 (file)
index 0000000..3c920af
--- /dev/null
@@ -0,0 +1,165 @@
+define([], function () {
+    'use strict';
+
+    angular.module('app.yangman').directive('uiCodemirror', uiCodemirrorDirective);
+
+    /**
+     * @ngInject
+     */
+    function uiCodemirrorDirective($timeout, ymUiCodemirrorConfig) {
+
+        return {
+            restrict: 'EA',
+            require: '?ngModel',
+            compile: function compile() {
+
+                // Require CodeMirror
+                if (angular.isUndefined(window.CodeMirror)) {
+                    throw new Error('ui-codemirror needs CodeMirror to work... (o rly?)');
+                }
+
+                return postLink;
+            }
+        };
+
+        function postLink(scope, iElement, iAttrs, ngModel) {
+            var codemirrorOptions = angular.extend(
+                {value: iElement.text()},
+                ymUiCodemirrorConfig.codemirror || {},
+                scope.$eval(iAttrs.uiCodemirror),
+                scope.$eval(iAttrs.uiCodemirrorOpts)
+            );
+
+            var codemirror = newCodemirrorEditor(iElement, codemirrorOptions);
+
+            configOptionsWatcher(
+                codemirror,
+                iAttrs.uiCodemirror || iAttrs.uiCodemirrorOpts,
+                scope
+            );
+
+            configNgModelLink(codemirror, ngModel, scope);
+
+            configUiRefreshAttribute(codemirror, iAttrs.uiRefresh, scope);
+
+            // Allow access to the CodeMirror instance through a broadcasted event
+            // eg: $broadcast('CodeMirror', function(cm){...});
+            scope.$on('CodeMirror', function (event, callback) {
+                if (angular.isFunction(callback)) {
+                    callback(codemirror);
+                } else {
+                    throw new Error('the CodeMirror event requires a callback function');
+                }
+            });
+
+            // onLoad callback
+            if (angular.isFunction(codemirrorOptions.onLoad)) {
+                codemirrorOptions.onLoad(codemirror);
+            }
+        }
+
+        function newCodemirrorEditor(iElement, codemirrorOptions) {
+            var codemirrot;
+
+            if (iElement[0].tagName === 'TEXTAREA') {
+                // Might bug but still ...
+                codemirrot = window.CodeMirror.fromTextArea(iElement[0], codemirrorOptions);
+            } else {
+                iElement.html('');
+                codemirrot = new window.CodeMirror(function (cm_el) {
+                    iElement.append(cm_el);
+                }, codemirrorOptions);
+            }
+
+            return codemirrot;
+        }
+
+        function configOptionsWatcher(codemirrot, uiCodemirrorAttr, scope) {
+            if (!uiCodemirrorAttr) {
+                return;
+            }
+
+            var codemirrorDefaultsKeys = Object.keys(window.CodeMirror.defaults);
+            scope.$watch(uiCodemirrorAttr, updateOptions, true);
+            function updateOptions(newValues, oldValue) {
+                if (!angular.isObject(newValues)) {
+                    return;
+                }
+                codemirrorDefaultsKeys.forEach(function (key) {
+                    if (newValues.hasOwnProperty(key)) {
+
+                        if (oldValue && newValues[key] === oldValue[key]) {
+                            return;
+                        }
+
+                        codemirrot.setOption(key, newValues[key]);
+                    }
+                });
+            }
+        }
+
+        function configNgModelLink(codemirror, ngModel, scope) {
+            if (!ngModel) {
+                return;
+            }
+            // CodeMirror expects a string, so make sure it gets one.
+            // This does not change the model.
+            ngModel.$formatters.push(function (value) {
+                if (angular.isUndefined(value) || value === null) {
+                    return '';
+                } else if (angular.isObject(value) || angular.isArray(value)) {
+                    throw new Error('ui-codemirror cannot use an object or an array as a model');
+                }
+                return value;
+            });
+
+
+            // Override the ngModelController $render method, which is what gets called when the model is updated.
+            // This takes care of the synchronizing the codeMirror element with the underlying model, in the case that it is changed by something else.
+            ngModel.$render = function () {
+                //Code mirror expects a string so make sure it gets one
+                //Although the formatter have already done this, it can be possible that another formatter returns undefined (for example the required directive)
+                var safeViewValue = ngModel.$viewValue || '';
+                codemirror.setValue(safeViewValue);
+            };
+
+
+            // Keep the ngModel in sync with changes from CodeMirror
+            codemirror.on('change', function (instance) {
+                var newValue = instance.getValue();
+                if (newValue !== ngModel.$viewValue) {
+                    scope.$evalAsync(function () {
+                        ngModel.$setViewValue(newValue);
+                    });
+                }
+            });
+
+
+            // Fix for using codemirror in tabs (or modal window)
+            codemirror.on('changes', function (instance, changes) {
+                $timeout(function () {
+                    instance.refresh();
+                });
+            });
+        }
+
+        function configUiRefreshAttribute(codeMirror, uiRefreshAttr, scope) {
+            if (!uiRefreshAttr) {
+                return;
+            }
+
+            scope.$watch(uiRefreshAttr, function (newVal, oldVal) {
+                // Skip the initial watch firing
+                if (newVal !== oldVal) {
+                    $timeout(function () {
+                        codeMirror.refresh();
+                    });
+                }
+            });
+        }
+
+    }
+
+    uiCodemirrorDirective.$inject = ['$timeout', 'ymUiCodemirrorConfig'];
+
+});
diff --git a/modules/yangman-resources/src/main/resources/yangman/directives/yang-form-menu.directive.js b/modules/yangman-resources/src/main/resources/yangman/directives/yang-form-menu.directive.js
new file mode 100644 (file)
index 0000000..585f4e4
--- /dev/null
@@ -0,0 +1,87 @@
+define(['angular'], function (angular) {
+    'use strict';
+
+    angular.module('app.yangman').directive('yangFormMenu', menuDirective);
+
+    menuDirective.$inject = [];
+
+    function menuDirective() {
+        return {
+            restrict: 'E',
+            templateUrl: 'src/app/yangman/views/directives/yang-form-menu.tpl.html',
+            scope: {
+                node: '=',
+                augmentations: '=',
+                allowItems: '=',
+                isActionMenu: '&',
+                addListItemFunc: '&',
+                addListItem: '=',
+                yangForm: '=',
+                yangList: '=',
+            },
+            controller: function ($scope) {
+                var lastSection = null;
+
+                $scope.infoBox = false;
+                $scope.infoBoxSection = '';
+                $scope.selectedListItem = 0;
+
+                // methods
+                $scope.switchSection = switchSection;
+                $scope.hideInfoBox = hideInfoBox;
+
+                /**
+                 * Switcher for info box section
+                 * @param section
+                 */
+                function switchSection(section){
+                    if ( $scope.infoBox ) {
+                        if ( section === lastSection ) {
+                            $scope.infoBox = false;
+                        } else {
+                            $scope.infoBoxSection = section;
+                        }
+                    } else {
+                        $scope.infoBox = true;
+                        $scope.infoBoxSection = section;
+                    }
+                    lastSection = section;
+                }
+
+                /**
+                 * Hide menu info box
+                 */
+                function hideInfoBox(){
+                    $scope.infoBox = false;
+                    angular.element('#infoBox').addClass('ng-hide');
+                }
+
+                $scope.$on('hideInfoBox', function () {
+                    hideInfoBox();
+                });
+            },
+            link: function (scope, element, attrs) {
+                scope.isActive = false;
+
+                // methods
+                scope.closeMenu = closeMenu;
+                scope.openMenu = openMenu;
+
+                /**
+                 * Close Yang menu
+                 */
+                function closeMenu(){
+                    scope.isActive = false;
+                }
+
+                /**
+                 * Open Yang menu
+                 */
+                function openMenu(){
+                    scope.isActive = true;
+                }
+
+            },
+        };
+    }
+});
diff --git a/modules/yangman-resources/src/main/resources/yangman/directives/ym-info-box.directive.js b/modules/yangman-resources/src/main/resources/yangman/directives/ym-info-box.directive.js
new file mode 100644 (file)
index 0000000..8acf862
--- /dev/null
@@ -0,0 +1,57 @@
+define(['angular'], function (angular) {
+    'use strict';
+
+    angular.module('app.yangman').directive('ymInfoBox', infoBoxDirective);
+
+    infoBoxDirective.$inject = [];
+
+    function infoBoxDirective() {
+        return {
+            restrict: 'A',
+            templateUrl: 'src/app/yangman/views/directives/ym-info-box.tpl.html',
+            transclude: true,
+            scope: {
+                node: '=',
+            },
+            link: function (scope, element) {
+                element.addClass('info-box-container');
+            },
+            controller: function ($scope) {
+                var description = $scope.node.getChildren('description', null, null, 'label')[0];
+
+                $scope.description = description ? description : '';
+                $scope.infoBox = false;
+
+                // methods
+                $scope.dividerCheck = dividerCheck;
+                $scope.executeInfoBox = executeInfoBox;
+                $scope.showBoxCheck = showBoxCheck;
+
+                /**
+                 * Set info box value - true, false
+                 * @param value
+                 */
+                function executeInfoBox(value){
+                    $scope.infoBox = value;
+                }
+
+                /**
+                 * Check if box info could be shown
+                 * @returns {boolean|*}
+                 */
+                function showBoxCheck(){
+                    return $scope.infoBox && ($scope.description.length || $scope.node.augmentationId);
+                }
+
+                /**
+                 * Check for showing divider between different shown info
+                 * @param key
+                 * @returns {*}
+                 */
+                function dividerCheck(key){
+                    return key ? $scope.description.length || $scope.node.augmentationId : $scope.description.length;
+                }
+            },
+        };
+    }
+});
diff --git a/modules/yangman-resources/src/main/resources/yangman/main.js b/modules/yangman-resources/src/main/resources/yangman/main.js
new file mode 100644 (file)
index 0000000..7faad29
--- /dev/null
@@ -0,0 +1,4 @@
+require.config({
+});
+
+define(['app/yangman/yangman.module']);
diff --git a/modules/yangman-resources/src/main/resources/yangman/models/baselist.model.js b/modules/yangman-resources/src/main/resources/yangman/models/baselist.model.js
new file mode 100644 (file)
index 0000000..b896aad
--- /dev/null
@@ -0,0 +1,130 @@
+define([], function (){
+    'use strict';
+
+
+    /**
+     * Base list object for extending history and collection object
+     * @constructor
+     * @param ParsingJsonService
+     */
+    function BaseListModel($filter, ParsingJsonService) {
+
+        var self = this;
+
+        /**
+         * General list of all objects to simply treat them
+         * @type {Array}
+         */
+        self.list = [];
+        /**
+         * Simple list of selected items from self.list
+         * @type {Array}
+         */
+        self.selectedItems = [];
+
+        self.addFromJSON = addFromJSON;
+        self.addItemToList = addItemToList;
+        self.createItem = createItem;
+        self.loadListFromStorage = loadListFromStorage;
+        self.saveToStorage = saveToStorage;
+        self.setName = setName;
+        self.selectAllFilteredItems = selectAllFilteredItems;
+        self.deselectAllFilteredItems = deselectAllFilteredItems;
+        self.getSelectedItems = getSelectedItems;
+        self.deselectAllItems = deselectAllItems;
+
+        function deselectAllItems() {
+            self.list.forEach(function (item) {
+                item.selected = false;
+            });
+            self.selectedItems = [];
+        }
+
+        /**
+         * @returns {Array}
+         */
+        function getSelectedItems(filterFunc) {
+            if (filterFunc) {
+                return $filter('filter')(self.selectedItems, filterFunc);
+            }
+            else {
+                return self.selectedItems;
+            }
+        }
+
+        /**
+         * Mark all items matching filter as selected
+         * Toggle only items matching filter, other items let be as they are
+         * @param filterFunc function returning boolean
+         */
+        function selectAllFilteredItems(filterFunc) {
+            $filter('filter')(self.list, filterFunc).forEach(function (item) {
+                item.selected = true;
+                if (self.selectedItems.indexOf(item) === -1){
+                    self.selectedItems.push(item);
+                }
+            });
+        }
+
+        /**
+         * Mark all requests matching filter as deselected
+         * Toggle only requests matching filter, other requests let be as they are
+         * @param filterFunc
+         */
+        function deselectAllFilteredItems(filterFunc) {
+            $filter('filter')(self.list, filterFunc).forEach(function (item) {
+                item.selected = false;
+                self.selectedItems.splice(self.selectedItems.indexOf(item), 1);
+            });
+        }
+
+        function setName(name) {
+            self.name = name;
+        }
+
+        function createItem(elem) {
+            return elem;
+        }
+
+        function addItemToList(){}
+
+        /**
+         * Loading from localStorage
+         */
+        function loadListFromStorage(){
+            var storageList = localStorage.getItem(self.name);
+
+            if (storageList){
+                self.clear();
+                ParsingJsonService.parseJson(storageList).map(function (elem) {
+                    return self.createItem(elem);
+                }).forEach(function (elem) {
+                    self.addItemToList(elem);
+                });
+            }
+        }
+
+        /**
+         * Saving to local storage
+         */
+        function saveToStorage(){
+            try {
+                localStorage.setItem(self.name, JSON.stringify(self.toJSON()));
+            } catch (e) {
+            }
+        }
+
+        /**
+         * Add each request from json
+         * @param json
+         */
+        function addFromJSON(json) {
+            json.forEach(function (elem) {
+                var item = self.createItem(elem);
+                self.addItemToList(item);
+            });
+        }
+    }
+
+    return BaseListModel;
+});
diff --git a/modules/yangman-resources/src/main/resources/yangman/models/collection.model.js b/modules/yangman-resources/src/main/resources/yangman/models/collection.model.js
new file mode 100644 (file)
index 0000000..d4d653a
--- /dev/null
@@ -0,0 +1,35 @@
+define([], function (){
+    'use strict';
+
+    /**
+     * Collection object used in CollectionListModel
+     * @param name
+     * @constructor
+     */
+    function CollectionModel(name){
+        var self = this;
+        self.name = name;
+        self.expanded = false;
+        self.data = [];
+
+        self.clone = clone;
+        self.toggleExpanded = toggleExpanded;
+
+        function clone(newName){
+            var result = new CollectionModel(newName);
+            self.data.forEach(function (item){
+                var newItem = item.clone();
+                newItem.collection = newName;
+                result.data.push(newItem);
+            });
+            return result;
+        }
+
+        function toggleExpanded(){
+            self.expanded = !self.expanded;
+        }
+
+    }
+
+    return CollectionModel;
+});
diff --git a/modules/yangman-resources/src/main/resources/yangman/models/collectionlist.model.js b/modules/yangman-resources/src/main/resources/yangman/models/collectionlist.model.js
new file mode 100644 (file)
index 0000000..4e20ebb
--- /dev/null
@@ -0,0 +1,276 @@
+define(
+    ['app/yangman/models/baselist.model', 'app/yangman/models/collection.model'],
+    function (BaseListModel, CollectionModel){
+
+        'use strict';
+
+        /**
+         * Base collection list object
+         * @constructor
+         * @param ParsingJsonService
+         * @param RequestsService
+         */
+        function CollectionListModel($filter, ParsingJsonService, RequestsService){
+
+            BaseListModel.call(this, $filter, ParsingJsonService);
+
+            /* jshint validthis: true */
+            var self = this;
+
+            /**
+             * Array of collections in which are requests from self.list groupped
+             * @type {Array}
+             */
+            self.collections = [];
+
+            self.addItemToList = addItemToList;
+            self.clear = clear;
+            self.collectionExists = collectionExists;
+            self.createItem = createItem;
+            self.deleteCollection = deleteCollection;
+            self.deleteRequestItem = deleteRequestItem;
+            self.duplicateCollection = duplicateCollection;
+            self.getCollection = getCollection;
+            self.getCollectionNames = getCollectionNames;
+            self.loadListFromFile = loadListFromFile;
+            self.renameCollection = renameCollection;
+            self.toggleReqSelection = toggleReqSelection;
+            self.toJSON = toJSON;
+            self.getCollectionInJSON = getCollectionInJSON;
+            self.getExpandedCollectionNames = getExpandedCollectionNames;
+            self.expandCollectionByNames = expandCollectionByNames;
+            self.getCollectionInRawJSON = getCollectionInRawJSON;
+
+            /**
+             *
+             * @param collectionName
+             */
+            function getCollectionInJSON(collectionName){
+                return JSON.stringify(self.toJSON(collectionName));
+            }
+
+            function getCollectionInRawJSON(collectionName){
+                return self.toJSON(collectionName);
+            }
+
+
+            /**
+             * @param collObj
+             */
+            function deleteCollection(collObj){
+
+                var colIndex = self.collections.indexOf(collObj);
+                // first check if collObj is the same as got by index to prevent delete wrong collection because of the
+                // asynchron processes (when user is pressing enter many times, this method could be called more times
+                // and in some other proceeding might be this collection already deleted)
+                if (self.collections[colIndex] && self.collections[colIndex].name === collObj.name){
+                    self.collections.splice(colIndex, 1);
+                }
+            }
+
+            /**
+             *
+             * @param srcColName
+             * @param destColName
+             */
+            function duplicateCollection(srcColName, destColName){
+                var newCol = self.getCollection(srcColName).clone(destColName);
+                self.collections.push(newCol);
+            }
+
+            /**
+             *
+             * @param collObj
+             * @param name
+             */
+            function setCollObjNewName(collObj, newName){
+                collObj.name = newName;
+                collObj.data.forEach(function (item){
+                    item.collection = newName;
+                });
+            }
+
+            /**
+             * Mark reqObj as selected
+             * @param reqObj HistoryRequest object to be selected
+             */
+            function toggleReqSelection(onlyOneSelected, reqObj){
+                if (onlyOneSelected){
+                    self.selectedItems.forEach(function (req){
+                        req.selected = false;
+                    });
+                    self.selectedItems = [];
+                }
+
+                if (reqObj.selected && !onlyOneSelected){
+                    self.selectedItems.splice(self.selectedItems.indexOf(reqObj), 1);
+                }
+
+                reqObj.selected = (reqObj.selected && onlyOneSelected) || !reqObj.selected;
+                if (reqObj.selected){
+                    self.selectedItems.push(reqObj);
+                }
+            }
+
+            /**
+             *
+             * @param oldName
+             * @param newName
+             */
+            function renameCollection(oldName, newName){
+                var col = self.getCollection(oldName);
+                setCollObjNewName(col, newName);
+            }
+
+            /**
+             *
+             * @param elem
+             * @returns {HistoryRequest|*}
+             */
+            function createItem(elem) {
+                return RequestsService.createHistoryRequestFromElement(elem);
+            }
+
+            /**
+             *
+             * @param {string} colName
+             * @returns {boolean}
+             */
+            function collectionExists(colName) {
+                return self.collections.some(function (col){
+                    return col.name === colName;
+                });
+            }
+
+            /**
+             *
+             * @returns {Array}
+             */
+            function getCollectionNames(){
+                return self.collections.map(function (elem){
+                    return elem.name;
+                });
+            }
+
+            /**
+             *
+             * @param colName
+             * @returns {T}
+             */
+            function getCollection(colName){
+                return self.collections.filter(function (col){
+                    return col.name === colName;
+                })[0];
+            }
+
+
+            /**
+             *
+             * @param reqObj
+             */
+            function addItemToList(reqObj){
+                self.list.push(reqObj);
+                if (reqObj.collection) {
+                    var col = null;
+                    if (self.collectionExists(reqObj.collection)) {
+                        col = self.getCollection(reqObj.collection);
+                    }
+                    else {
+                        col = new CollectionModel(reqObj.collection);
+                        self.collections.push(col);
+                    }
+                    col.data.push(reqObj);
+                }
+            }
+
+
+            /**
+             *
+             * @param elem
+             */
+            function deleteRequestItem(elem){
+                var col = self.getCollection(elem.collection);
+                col.data.splice(col.data.indexOf(elem), 1);
+                if (col.data.length === 0){
+                    self.collections.splice(self.collections.indexOf(col), 1);
+                }
+
+            }
+
+            function clear() {
+                self.collections = [];
+                self.selectedItems = [];
+                self.list = [];
+            }
+
+            /**
+             *
+             * @param collectionName
+             * @returns {*}
+             */
+            function toJSON(collectionName) {
+                if (collectionName){
+                    return self.getCollection(collectionName).data.map(function (elem){
+                        return elem.toJSON();
+                    });
+                }
+                else {
+                    var list = [];
+                    self.collections.forEach(function (collection){
+                        collection.data.forEach(function (elem){
+                            list.push(elem.toJSON());
+                        });
+                    });
+                    return list;
+                }
+            }
+
+            /**
+             *
+             * @param data
+             */
+            function loadListFromFile(data){
+                if (data){
+                    ParsingJsonService.parseJson(data).map(function (elem) {
+                        return RequestsService.createHistoryRequest(elem.sentData, elem.receivedData, elem.path,
+                            elem.method, elem.status, elem.name, elem.collection);
+                    }).forEach(function (elem) {
+                        self.addItemToList(elem);
+                    });
+                }
+            }
+
+            /**
+             * Get expanded collection names
+             */
+            function getExpandedCollectionNames(){
+                return self.collections.filter(function(collection){
+                    return collection.expanded;
+                }).map(function(collection){
+                    return collection.name;
+                });
+            }
+
+            /**
+             * Expand collections by expandCollectionNames
+             */
+            function expandCollectionByNames(expandCollectionNames){
+                self.collections.forEach(function(collection){
+                    if (findName(collection.name)) {
+                        collection.expanded = true;
+                    }
+                });
+
+                function findName(name) {
+                    return expandCollectionNames.some(function(collectionName){
+                        return name === collectionName;
+                    });
+                }
+            }
+
+        }
+        CollectionListModel.prototype = Object.create(BaseListModel.prototype);
+
+        return CollectionListModel;
+    }
+);
diff --git a/modules/yangman-resources/src/main/resources/yangman/models/history-request.model.js b/modules/yangman-resources/src/main/resources/yangman/models/history-request.model.js
new file mode 100644 (file)
index 0000000..4af7bb8
--- /dev/null
@@ -0,0 +1,166 @@
+define([], function (){
+    'use strict';
+
+    /**
+     * Base history request object
+     * @constructor
+     * @param PathUtilsService
+     * @param YangUtilsService
+     * @param ParsingJsonService
+     */
+    function HistoryRequestModel(PathUtilsService, YangUtilsService, ParsingJsonService){
+        var self = this;
+
+        // properties
+        self.collection = '';
+        self.method = '';
+        self.name = '';
+        self.path = '';
+        self.receivedData = null;
+        self.selected = false;
+        self.sentData = null;
+        self.status = '';
+        self.timestamp = '';
+        self.responseStatus = '';
+        self.responseStatusText = '';
+        self.responseTime = '';
+
+        // functions
+        self.clone = clone;
+        self.toJSON = toJSON;
+        self.getLastPathDataElemName = getLastPathDataElemName;
+        self.setDataForView = setDataForView;
+        self.setData = setData;
+        self.setExecutionData = setExecutionData;
+
+        /**
+         * Grouped setter
+         *
+         * @param sentData
+         * @param receivedData
+         * @param status
+         * @param path
+         * @param operation
+         * @param name
+         * @param collection
+         * @param timestamp
+         * @param responseStatus
+         * @param responseTime
+         * @param responseStatusText
+         */
+        function setData(sentData, receivedData, status, path, operation, name, collection, timestamp, responseStatus, responseStatusText, responseTime) {
+
+            self.sentData = sentData === null || sentData === undefined || $.isEmptyObject(sentData) ? null : sentData;
+            self.name = name;
+            self.path = path;
+            self.method = operation;
+            self.status = status;
+            self.receivedData = receivedData === null || receivedData === undefined || $.isEmptyObject(receivedData) ?
+                null : receivedData;
+            self.collection = collection;
+            self.timestamp = timestamp;
+            self.responseStatus = responseStatus;
+            self.responseStatusText = responseStatusText;
+            self.responseTime = responseTime;
+        }
+
+        /**
+         * Set data which might be available after executing request
+         * @param sentData
+         * @param receivedData
+         * @param status - http status from response header
+         * @param responseStatus
+         * @param responseTime
+         * @param responseStatusText
+         */
+        function setExecutionData(sentData, receivedData, status, responseStatus, responseStatusText, responseTime) {
+            self.sentData = sentData;
+            self.receivedData = receivedData;
+            self.status = status ? (status > 199 && status < 205 ? 'success' : 'erorr') : '';
+            self.responseStatus = responseStatus;
+            self.responseStatusText = responseStatusText;
+            self.responseTime = responseTime;
+        }
+
+
+        /**
+         *
+         * @returns {{sentData: (null|*), receivedData: (null|*), path: (string|*), collection: (string|*),
+         * method: (string|*), status: (string|*), name: (string|*), timestamp: (string|*), responseStatus: (string|*),
+         * responseTime: (string|*)}}
+         */
+        function toJSON() {
+            var obj = {
+                sentData: self.sentData,
+                receivedData: self.receivedData,
+                path: self.path,
+                collection: self.collection,
+                method: self.method,
+                status: self.status,
+                name: self.name,
+                timestamp: self.timestamp,
+                responseStatus: self.responseStatus,
+                responseStatusText: self.responseStatusText,
+                responseTime: self.responseTime,
+            };
+
+            return obj;
+        }
+
+
+
+        /**
+         *
+         * @returns {*}
+         */
+        function getLastPathDataElemName() {
+            var pathArray = self.path.split(':');
+            return pathArray[pathArray.length - 1];
+        }
+
+        /**
+         *
+         * @param data
+         * @returns {string}
+         */
+        function setDataForView(data){
+            var result = '';
+
+            if (data instanceof Object) {
+                result = JSON.stringify(
+                    YangUtilsService.stripAngularGarbage(
+                        angular.copy(data),
+                        self.getLastPathDataElemName()
+                    ),
+                    null,
+                    4
+                );
+            }
+            else {
+                result = data;
+            }
+
+            return result;
+
+        }
+
+
+        /**
+         *
+         * @returns {HistoryRequest}
+         */
+        function clone() {
+            /**
+             *
+             * @type {HistoryRequestModel}
+             */
+            var result = new HistoryRequestModel(PathUtilsService, YangUtilsService, ParsingJsonService);
+            result.setData(self.sentData, self.receivedData, self.status, self.path, self.method, self.name,
+                self.collection, self.timestamp, self.responseStatus, self.responseStatusText, self.responseTime);
+            return result;
+        }
+
+    }
+
+    return HistoryRequestModel;
+});
diff --git a/modules/yangman-resources/src/main/resources/yangman/models/historylist.model.js b/modules/yangman-resources/src/main/resources/yangman/models/historylist.model.js
new file mode 100644 (file)
index 0000000..62cd60c
--- /dev/null
@@ -0,0 +1,172 @@
+define(['app/yangman/models/baselist.model'], function (BaseListModel){
+    'use strict';
+
+    /**
+     * Base history list object
+
+     * @constructor
+     * @param ParsingJsonService
+     * @param RequestsService
+     */
+    function HistoryListModel($filter, ParsingJsonService, RequestsService){
+
+        BaseListModel.call(this, $filter, ParsingJsonService);
+
+        /* jshint validthis: true */
+        var self = this;
+
+
+        /**
+         * Array of groups in which are requests from self.list groupped
+         * @type {Array}
+         */
+        self.dateGroups = [];
+
+        self.addItemToList = addItemToList;
+        self.clear = clear;
+        self.createItem = createItem;
+        self.deleteRequestItem = deleteRequestItem;
+        self.deselectReqs = deselectReqs;
+        self.selectReqs = selectReqs;
+        self.toggleReqSelection = toggleReqSelection;
+        self.getNewestRequest = getNewestRequest;
+
+
+        /**
+         * Get request with max timestamp (was executed as the last)
+         */
+        function getNewestRequest() {
+            return $filter('orderBy')(self.list, '-timestamp')[0];
+        }
+
+        /**
+         * Mark reqObj as selected
+         * @param {boolean} onlyOneSelected boolean if only this object should be marked as selected
+         * @param reqObj HistoryRequest object to be selected
+         */
+        function toggleReqSelection(onlyOneSelected, reqObj){
+            if (onlyOneSelected){
+                self.selectedItems.forEach(function (req){
+                    req.selected = false;
+                });
+                self.selectedItems = [];
+            }
+
+            if (reqObj.selected && !onlyOneSelected){
+                self.selectedItems.splice(self.selectedItems.indexOf(reqObj), 1);
+            }
+
+            reqObj.selected = (reqObj.selected && onlyOneSelected) || !reqObj.selected;
+            if (reqObj.selected){
+                self.selectedItems.push(reqObj);
+            }
+
+        }
+
+        /**
+         * Round timestamp to day
+         * @param timeStamp
+         * @returns {number|*}
+         */
+        function roundTimestampToDate(timeStamp){
+            timeStamp -= timeStamp % (24 * 60 * 60 * 1000);//subtract amount of time since midnight
+            timeStamp += new Date().getTimezoneOffset() * 60 * 1000;//add on the timezone offset
+            return timeStamp;
+        }
+
+        /**
+         * Add element to date group
+         * @param elem
+         */
+        function addElemToListDateGroup(elem){
+            if (elem.timestamp){
+                var groupName = roundTimestampToDate(elem.timestamp),
+                    dateGroupArr = self.dateGroups.filter(function (group){
+                        return group.name === groupName;
+                    }),
+                    dateGroup = null;
+
+                if (dateGroupArr.length){
+                    dateGroup = dateGroupArr[0];
+                }
+                else {
+                    dateGroup = {
+                        name: groupName,
+                        longName: new Date(groupName).toDateString(),
+                        requests: [],
+                    };
+                    self.dateGroups.push(dateGroup);
+                }
+                dateGroup.requests.push(elem);
+            }
+        }
+
+
+        /**
+         *
+         * @param elem
+         * @returns {HistoryRequest|*}
+         */
+        function createItem(elem) {
+            return RequestsService.createHistoryRequestFromElement(elem);
+        }
+
+        /**
+         *
+         * @param reqObj
+         */
+        function addItemToList(reqObj){
+            self.list.push(reqObj);
+            addElemToListDateGroup(reqObj);
+        }
+
+        /**
+         *
+         * @param elem
+         */
+        function deleteRequestItem(elem){
+            self.list.splice(self.list.indexOf(elem), 1);
+        }
+
+        function clear() {
+            self.list = [];
+            self.dateGroups = [];
+            self.selectedItems = [];
+        }
+
+        /**
+         *
+         * @returns {Array}
+         */
+        self.toJSON = function () {
+            return self.list.map(function (elem) {
+                return elem.toJSON();
+            });
+        };
+
+        /**
+         * Mark all history requests as deselected
+         */
+        function deselectReqs(){
+            self.selectedItems.forEach(function (request){
+                request.selected = false;
+            });
+            self.selectedItems = [];
+        }
+
+        /**
+         * Mark all history requests as selected
+         */
+        function selectReqs(requestsList){
+            requestsList.forEach(function (reqObj){
+                reqObj.selected = true;
+                self.selectedItems.push(reqObj);
+            });
+        }
+    }
+
+    HistoryListModel.prototype = Object.create(BaseListModel.prototype);
+
+    return HistoryListModel;
+
+});
diff --git a/modules/yangman-resources/src/main/resources/yangman/models/parameter.model.js b/modules/yangman-resources/src/main/resources/yangman/models/parameter.model.js
new file mode 100644 (file)
index 0000000..294d76a
--- /dev/null
@@ -0,0 +1,74 @@
+define([], function (){
+    'use strict';
+
+    /**
+     * Base parameter object
+     * @constructor
+     */
+    function ParameterModel(){
+        var self = this;
+
+        // properties
+        self.name = '';
+        self.value = '';
+
+        // attributes with underscore prefix are used for filtering in params admin
+        self._name = '';
+        self._value = '';
+
+        // functions
+        self.toJSON = toJSON;
+        self.setData = setData;
+        self.clone = clone;
+        self.applyValsForFilters = applyValsForFilters;
+
+        /**
+         * Copy model name and value to _name and _value properties, which are used when sorting and filtering list
+         * of parameters
+         */
+        function applyValsForFilters() {
+            self._name = self.name;
+            self._value = self.value;
+        }
+
+        /**
+         * Grouped setter
+         *
+         * @param name
+         * @param value
+         */
+        function setData(name, value) {
+            self.name = name;
+            self.value = value;
+            self._name = name;
+            self._value = value;
+        }
+
+        /**
+         *
+         * @returns {{name: (string|*), value: (string|*)}}
+         */
+        function toJSON() {
+            var obj = {
+                name: self.name,
+                value: self.value,
+            };
+
+            return obj;
+        }
+
+        /**
+         *
+         * @returns {ParameterModel}
+         */
+        function clone() {
+            var result = new ParameterModel();
+            result.setData(self.name, self.val);
+            return result;
+        }
+
+
+    }
+
+    return ParameterModel;
+});
diff --git a/modules/yangman-resources/src/main/resources/yangman/models/parameterslist.model.js b/modules/yangman-resources/src/main/resources/yangman/models/parameterslist.model.js
new file mode 100644 (file)
index 0000000..d3a1b16
--- /dev/null
@@ -0,0 +1,150 @@
+define(['app/yangman/models/baselist.model'], function (BaseListModel){
+    'use strict';
+
+    /**
+     * Base parameters list object
+     * @constructor
+     * @param ParsingJsonService
+     * @param ParametersService
+     */
+    function ParametersListModel($filter, ParsingJsonService, ParametersService){
+
+        BaseListModel.call(this, $filter, ParsingJsonService);
+
+        /* jshint validthis: true */
+        var self = this;
+        self.list = [];
+
+        self.addItemToList = addItemToList;
+        self.clear = clear;
+        self.createItem = createItem;
+        self.deleteParameterItem = deleteParameterItem;
+        self.setName = setName;
+        self.addEmptyItem = addEmptyItem;
+        self.toJSON = toJSON;
+        self.createParamsFromJson = createParamsFromJson;
+        self.isNameUnique = isNameUnique;
+        self.removeEmptyParams = removeEmptyParams;
+        self.applyValsForFilters = applyValsForFilters;
+
+        /**
+         * Apply all parameters names and values for filtering
+         */
+        function applyValsForFilters() {
+            self.list.forEach(function (param) {
+                param.applyValsForFilters();
+            });
+        }
+
+        /**
+         * Returns false if name is already used
+         * @param nameValue
+         * @returns {boolean}
+         */
+        function isNameUnique(nameValue) {
+            return !nameValue || self.list.filter(function (item) {
+                return item.name === nameValue;
+            }).length === 1;
+        }
+
+        /**
+         * Using when importing data from json file
+         * @param data
+         */
+        function createParamsFromJson(data){
+            if (data){
+                self.clear();
+                ParsingJsonService.parseJson(data).map(function (elem) {
+                    return ParametersService.createParameter(elem);
+                }).forEach(function (elem) {
+                    self.addItemToList(elem);
+                });
+            }
+        }
+
+        /**
+         * Get all parameters in json for exporting
+         * @returns {Array}
+         */
+        function toJSON() {
+            return self.list.map(function (param){
+                return param.toJSON();
+            });
+        }
+
+        /**
+         * Set list name
+         * @param name
+         */
+        function setName(name) {
+            self.name = name;
+        }
+
+        /**
+         * Add empty param to list
+         */
+        function addEmptyItem() {
+            self.addItemToList(self.createItem());
+        }
+
+        function removeEmptyParams() {
+            self.list = self.list.filter(function (param) {
+                return param.name && param.name.length > 0;
+            });
+        }
+
+        /**
+         *
+         * @param elem
+         * @returns {Parameter|*}
+         */
+        function createItem(element) {
+            if (!element){
+                element = {
+                    name: '',
+                    value: '',
+                };
+            }
+            return ParametersService.createParameter(element);
+        }
+
+        /**
+         *
+         * @param paramObj
+         */
+        function addItemToList(paramObj){
+            self.list.push(paramObj);
+        }
+
+        /**
+         *
+         * @param paramObj
+         */
+        function deleteParameterItem(paramObj){
+            self.list.splice(self.list.indexOf(paramObj), 1);
+        }
+
+        function clear() {
+            self.list = [];
+        }
+
+        /**
+         *
+         * @returns {Array}
+         */
+        self.toJSON = function () {
+            return self.list.filter(notEmptyParam).map(function (elem) {
+                return elem.toJSON();
+            });
+
+            function notEmptyParam(item){
+                return item.name;
+            }
+        };
+    }
+
+    ParametersListModel.prototype = Object.create(BaseListModel.prototype);
+
+    return ParametersListModel;
+
+});
diff --git a/modules/yangman-resources/src/main/resources/yangman/services/handle-file.services.js b/modules/yangman-resources/src/main/resources/yangman/services/handle-file.services.js
new file mode 100644 (file)
index 0000000..cc33a84
--- /dev/null
@@ -0,0 +1,48 @@
+define([], function () {
+    'use strict';
+
+    angular.module('app.yangman').service('YMHandleFileService', YMHandleFileService);
+
+    YMHandleFileService.$inject = ['$window'];
+
+    function YMHandleFileService($window){
+        var service = {
+            downloadFile: downloadFile,
+        };
+
+        return service;
+
+        /**
+         * Service for preparing file and creating link for downloading
+         * @param filename
+         * @param data
+         * @param format
+         * @param charset
+         * @param successCbk
+         * @param errorCbk
+         */
+        function downloadFile(filename, data, format, charset, successCbk, errorCbk){
+            try {
+                var blob = new Blob([JSON.stringify(data, null, 4)], { type: 'application/' + format + '; ' + charset + ';' }),
+                    downloadLink = angular.element('<a></a>');
+
+                var clickEvent = new MouseEvent('click', {
+                    'view': window,
+                    'bubbles': true,
+                    'cancelable': false
+                });
+
+                downloadLink.attr('href', window.URL.createObjectURL(blob));
+                if(downloadLink.attr('download', filename) !== undefined) {
+                    downloadLink[0].dispatchEvent(clickEvent);
+                    successCbk();
+                }
+                else {
+                    $window.location.href = downloadLink[0].href;
+                }
+            } catch (e) {
+                errorCbk(e);
+            }
+        }
+    }
+});
diff --git a/modules/yangman-resources/src/main/resources/yangman/services/mount-points-connector.services.js b/modules/yangman-resources/src/main/resources/yangman/services/mount-points-connector.services.js
new file mode 100644 (file)
index 0000000..e668188
--- /dev/null
@@ -0,0 +1,203 @@
+define([
+    'common/yangutils/constants',
+], function (constants) {
+    'use strict';
+
+    angular.module('app.yangman').service('MountPointsConnectorService', MountPointsConnectorService);
+
+    MountPointsConnectorService.$inject = [
+        'YangUiApisService', 'NodeWrapperService',
+        'YangUtilsService', 'EventDispatcherService',
+        'YinParserService', 'PathUtilsService', 'YangUtilsRestangularService',
+    ];
+
+    function MountPointsConnectorService(
+        YangUiApisService, NodeWrapperService,
+        YangUtilsService, EventDispatcherService,
+        YinParserService, PathUtilsService, YangUtilsRestangularService){
+
+        var mountPrefix = constants.MPPREFIX,
+            service = {
+                addPathElemsToPathArray: addPathElemsToPathArray,
+                alterMpPath: alterMpPath,
+                createCustomButton: createCustomButton,
+                createMPRootNode: createMPRootNode,
+                discoverMountPoints: discoverMountPoints,
+                getMPModulesAPI: getMPModulesAPI,
+                updateMountPointApis: updateMountPointApis,
+            };
+
+        return service;
+
+        // TODO: add service's description
+        function createMPRootNode(mpNodes) {
+            var node = null,
+                yangParser = YinParserService.yangParser;
+
+            yangParser.setCurrentModuleObj(new YinParserService.Module('yang-ext', null, null));
+            node = yangParser.createNewNode('mount', 'container', null, constants.NODE_UI_DISPLAY);
+            NodeWrapperService.wrapAll(node);
+
+            node.buildRequest = function (builder, req, module) {
+                var added = false,
+                    builderNodes = node.getChildren(null, null, constants.NODE_UI_DISPLAY);
+
+                if (builderNodes.length) {
+                    builderNodes.forEach(function (child) {
+                        var childAdded = child.buildRequest(builder, req, module);
+                    });
+                }
+
+                return added;
+            };
+
+            node.fill = function (name, data) {
+                var nodesToFill = node.getChildren(null, null, constants.NODE_UI_DISPLAY);
+
+                nodesToFill.forEach(function (child) {
+                    var childFilled = child.fill(name, data);
+                });
+            };
+
+
+            mpNodes.forEach(function (mp){
+                node.addChild(mp);
+            });
+
+            return node;
+        }
+
+        // TODO: add service's description
+        function addPathElemsToPathArray(pathElems, pathArray, index) {
+            var updatedPath = pathArray.slice();
+
+            pathElems.forEach(function (pe, offset) {
+                // pe.disabled = true; //add disabled flag so user won't be able to change it in the UI
+                updatedPath.splice(index + offset, 0, pe);
+            });
+
+            return updatedPath;
+        }
+
+        // TODO: add service's description
+        function alterMpPath(path) {
+            var pathParts = path.split('/'),
+                restconfIndex = PathUtilsService.findIndexOfStrInPathStr(pathParts, 'restconf'),
+                mpIndex = PathUtilsService.findIndexOfStrInPathStr(pathParts, mountPrefix),
+                mpPath = path.slice(),
+                mpPathParts = '';
+
+            if (mpIndex !== -1){
+                mpPathParts = pathParts.slice(mpIndex);
+
+                var unshiftIndex = restconfIndex !== -1 ? restconfIndex + 1 : 0;
+
+                mpPathParts.unshift(pathParts[unshiftIndex]);
+                mpPath = mpPathParts.join('/');
+            }
+
+            return mpPath;
+        }
+
+        /**
+         * function for adding path to mountpoint + yang:ext-mount to mount point patharray so the request string
+         * will be built correctly
+         * @param basePathArray
+         * @param mpApis
+         */
+        function updateMountPointApis(basePathArray, mpApis) {
+            var actualPath = basePathArray.slice(1); // we don't want to have config/operational storage in path
+            // actualPath.push(PathUtilsService.createPathElement(mountPrefix, null, null, false));
+            // we want to push yang-ext:mount to the path - not if we have yang-ext:mount rootNode
+
+            mpApis.forEach(function (api) {
+                api.subApis.forEach(function (subApi) {
+                    subApi.pathArray = addPathElemsToPathArray(actualPath, subApi.pathArray, 1);
+                });
+            });
+        }
+
+        // TODO: add service's description
+        function getMPModulesAPI(api) {
+            var apiArray = api.split('/'),
+                yangExtMountStr = mountPrefix;
+
+            if (apiArray[apiArray.length - 1] !== yangExtMountStr) {
+                apiArray.push(yangExtMountStr);
+            }
+
+            return apiArray.slice(1).join('/');
+        }
+
+        // TODO: add service's description
+        function discoverMountPoints(api, getModulesCbk, callback) {
+            var modulesCbk = getModulesCbk || angular.noop,
+                mpNodes = [],
+                baseApiPath = getMPModulesAPI(api),
+                time = {
+                    started: 0,
+                    finished: 0,
+                };
+
+            YangUtilsRestangularService.setFullResponse(true);
+
+            time.started = new Date().getMilliseconds();
+
+            return YangUiApisService.getCustomModules(baseApiPath).then(
+                function (response) {
+                    time.finished = new Date().getMilliseconds();
+
+                    var reqObj = {
+                        status: response.status,
+                        statusText: response.statusText,
+                        time: (time.finished - time.started),
+                    };
+
+                    YangUtilsService.processModulesMP(response.data.modules, baseApiPath, function (result, augments) {
+                        EventDispatcherService.dispatch(constants.EV_SRC_MAIN, 'Linking modules to Apis');
+                        var allRootNodes = result.map(function (node) {
+                            var copy = node.deepCopy(['augmentionGroups', 'augmentationId']);
+
+                            NodeWrapperService.wrapAll(copy);
+                            return copy;
+                        });
+
+                        var moduleNames = response.data.modules.module.map(function (m) {
+                            return m.name;
+                        });
+
+                        allRootNodes.forEach(function (n) {
+                            if (moduleNames.indexOf(n.module) > -1 && ['container', 'list'].indexOf(n.type) > -1) {
+                                mpNodes.push(n);
+                            }
+                        });
+
+                        callback(mpNodes, augments, reqObj);
+                        YangUtilsRestangularService.setFullResponse(false);
+                    });
+                },
+                function (response) {
+                    time.finished = new Date().getMilliseconds();
+
+                    var reqObj = {
+                        status: response.status,
+                        statusText: response.statusText,
+                        time: (time.finished - time.started),
+                    };
+
+                    callback([], [], reqObj);
+                    YangUtilsRestangularService.setFullResponse(false);
+                });
+        }
+
+        // TODO: add service's description
+        function createCustomButton(label, show, click){
+            return {
+                label: label,
+                show: show,
+                onclick: click,
+            };
+        }
+    }
+
+});
diff --git a/modules/yangman-resources/src/main/resources/yangman/services/parameters.services.js b/modules/yangman-resources/src/main/resources/yangman/services/parameters.services.js
new file mode 100644 (file)
index 0000000..7c7d3fd
--- /dev/null
@@ -0,0 +1,69 @@
+define([
+    'app/yangman/models/parameter.model',
+    'app/yangman/models/parameterslist.model',
+],
+    function (ParameterModel, ParametersListModel) {
+        'use strict';
+
+        angular.module('app.yangman').service('ParametersService', ParametersService);
+
+        ParametersService.$inject = ['$filter', 'ParsingJsonService'];
+
+        function ParametersService($filter, ParsingJsonService){
+
+            var service = {};
+
+            service.createEmptyParametersList = createEmptyParametersList;
+            service.createParameter = createParameter;
+            service.validateFile = validateFile;
+
+            /**
+             * Validating collection import file
+             * @param data
+             * @param checkArray
+             * @returns {*}
+             */
+            function validateFile(data, checkArray){
+                try {
+                    var obj = ParsingJsonService.parseJson(data);
+
+                    return obj && obj.every(function (el){
+                        return checkArray.every(function (arr){
+                            return el.hasOwnProperty(arr);
+                        });
+                    });
+                } catch (e) {
+                    return e;
+                }
+            }
+
+            /**
+             * Service for creating basic parameter object
+             * @returns {*}
+             * @param name
+             * @param value
+             */
+            function createParameter(element){
+                var result = new ParameterModel();
+                result.setData(element.name, element.value);
+                return result;
+            }
+
+
+            /**
+             * Service for creating empty parameters list
+             * @param name used as name in local storage
+             * @returns {*}
+             */
+            function createEmptyParametersList(name){
+                var result = new ParametersListModel($filter, ParsingJsonService, service);
+                result.setName(name);
+                return result;
+            }
+
+
+            return service;
+
+        }
+
+    });
diff --git a/modules/yangman-resources/src/main/resources/yangman/services/plugins-handler.services.js b/modules/yangman-resources/src/main/resources/yangman/services/plugins-handler.services.js
new file mode 100644 (file)
index 0000000..68820b6
--- /dev/null
@@ -0,0 +1,61 @@
+var yangmanPluginsFactories = [
+    'ymDisplayMountPoints',
+];
+
+var yangmanPluginContollers = [
+];
+
+define([
+    'common/yangutils/services/custom-funct.services',
+].concat(yangmanPluginsFactories.map(function (plugin) {
+    'use strict';
+    return 'app/yangman/services/plugins/' + plugin + '.services';
+})).concat(yangmanPluginContollers.map(function (ctrl) {
+    'use strict';
+    return 'app/yangman/plugins/cv/' + ctrl + '.controller';
+})), function () {
+    'use strict';
+
+    angular.module('app.yangman').service('PluginsHandlerService', PluginsHandlerService);
+
+    function PluginsHandlerService($injector, CustomFuncService) {
+
+        var service = {
+            addPlugins: addPlugins,
+            plugAll: plugAll,
+            plugins: [],
+        };
+
+        service.addPlugins();
+
+        return service;
+
+        // TODO: add service's description
+        function addPlugins() {
+            yangmanPluginsFactories.forEach(function (pluginFactFullName) {
+                var pluginServiceName = pluginFactFullName.split('/'),
+                    pluginName = pluginServiceName[pluginServiceName.length - 1].split('.')[0];
+
+                $injector.invoke([pluginName, function (pluginFact) {
+                    service.plugins.push(pluginFact);
+                }]);
+            });
+
+        }
+
+        /**
+         * Method for importing additional plugins
+         * @param apis
+         */
+        function plugAll(apis) {
+            service.plugins.forEach(function (plugin) {
+                plugin.module.forEach(function (plModule, i){
+                    CustomFuncService.createCustomFunctionalityApis(apis, plModule, plugin.revision,
+                                                                    plugin.pathString[i], plugin.label,
+                                                                    plugin.getCallback, plugin.view,
+                                                                    plugin.hideButtonOnSelect);
+                });
+            });
+        }
+    }
+});
diff --git a/modules/yangman-resources/src/main/resources/yangman/services/plugins-unsetter.services.js b/modules/yangman-resources/src/main/resources/yangman/services/plugins-unsetter.services.js
new file mode 100644 (file)
index 0000000..347ae53
--- /dev/null
@@ -0,0 +1,55 @@
+define(['angular'], function (angular) {
+    'use strict';
+
+    angular.module('app.yangman').service('PluginsUnsetterService',
+        ['PathUtilsService', 'DataBackupService', PluginsUnsetterService]);
+
+    PluginsUnsetterService.$inject = ['constants'];
+
+    function PluginsUnsetterService(PathUtilsService, DataBackupService, constants){
+        var service = {
+            'YANGMAN_CUST_MOUNT_POINTS': unsetMountPoint,
+            unset: unset,
+        };
+
+        return service;
+
+        /**
+         * Method for unset mount point from application
+         * @param scope
+         */
+        function unsetMountPoint(scope){
+            var modulesListObj = {};
+
+            DataBackupService.getToScope(
+                [
+                    'selectedDatastore', 'node', 'apis',
+                    'selectedApi', 'selectedSubApi', 'augmentations', 'selectedModule',
+                ],
+                scope,
+                'MAIN_SCOPE'
+            );
+
+            DataBackupService.getToScope(['treeApis'], modulesListObj, 'MODULES_LIST');
+            scope.$broadcast(constants.YANGMAN_SET_API_TREE_DATA, { params: modulesListObj.treeApis });
+            scope.$broadcast(constants.YANGMAN_SET_MODULE_LIST_TITLE, { params: '' });
+
+            if ( scope.selectedDatastore ){
+                scope.$broadcast(constants.YANGMAN_MODULE_D_INIT);
+            }
+        }
+
+        /**
+         * General method for pick correct unset method for plugins
+         * @param scope
+         * @param controller
+         */
+        function unset(scope, controller) {
+            if (service.hasOwnProperty(controller.selectedPlugin.label)) {
+                service[controller.selectedPlugin.label](scope);
+            }
+        }
+
+    }
+
+});
diff --git a/modules/yangman-resources/src/main/resources/yangman/services/plugins/ymDisplayMountPoints.services.js b/modules/yangman-resources/src/main/resources/yangman/services/plugins/ymDisplayMountPoints.services.js
new file mode 100644 (file)
index 0000000..07cafd4
--- /dev/null
@@ -0,0 +1,134 @@
+define([
+    'app/yangman/services/mount-points-connector.services',
+], function (yangman) {
+    'use strict';
+
+    angular.module('app.yangman').service('ymDisplayMountPoints', DisplayMountPoints);
+
+    DisplayMountPoints.$inject =
+        ['MountPointsConnectorService', '$timeout', 'YangUtilsService', '$filter', 'ApiBuilderService', 'constants'];
+
+    function DisplayMountPoints(
+        MountPointsConnectorService, $timeout, YangUtilsService, $filter, ApiBuilderService, constants) {
+        var loadId = 0;
+
+        return {
+            module: ['network-topology', 'opendaylight-inventory', 'network-topology', 'opendaylight-inventory'],
+            revision: null,
+            pathString: [
+                'operational/network-topology:network-topology/topology/{topology-id}/node/{node-id}/',
+                'operational/opendaylight-inventory:nodes/node/{id}/',
+            ],
+            label: 'YANGMAN_CUST_MOUNT_POINTS',
+            hideButtonOnSelect: true,
+            getCallback: displayMountPointsCallback,
+        };
+
+        function displayMountPointsCallback(args) {
+            var controller = args.controller,
+                scope = args.scope,
+                path = scope.selectedSubApi.buildApiRequestString();
+
+            scope.rootBroadcast(constants.YANGMAN_SET_LOADING_BOX, true, function () {
+                scope.setLeftPanel(0);
+                $timeout(function () {
+                    MountPointsConnectorService.discoverMountPoints(path, getNodesMPData, createMPStructure);
+                }, 1000);
+            });
+
+            /**
+             * Get Mount point data from received raw data
+             * @param data
+             * @returns {*}
+             */
+            function getNodesMPData(data) {
+                var node = data.node[0];
+                return node && node['netconf-node-inventory:initial-capability'] ?
+                    node['netconf-node-inventory:initial-capability'].map(function (c) {
+                        return c.slice(c.lastIndexOf(')') + 1);
+                    }) : [];
+            }
+
+            // TODO :: description
+            function findFirstSubApiIndex(subApis) {
+                var firstConfigSubApiIndex = 0;
+
+                subApis.some(function (sa, index) {
+                    var condition = sa.storage === constants.DATA_STORE_CONFIG;
+                    if (condition) {
+                        firstConfigSubApiIndex = index;
+                    }
+                    return condition;
+                });
+
+                return firstConfigSubApiIndex;
+            }
+
+            /**
+             * Create base params for setup mount points in app
+             * @param mpNodes
+             * @param mpAugments
+             * @param reqObj
+             */
+            function createMPStructure(mpNodes, mpAugments, reqObj) {
+                if (mpNodes.length){
+                    var mpRootNode = MountPointsConnectorService.createMPRootNode(mpNodes),
+                        mountPointApis = ApiBuilderService.processAllRootNodes([mpRootNode]),
+                    // root node has isConfigStm undefined, we need to create root config SubApi by hand
+                    // if we set the variable isConfigStm to true and then generate the subApis it will do it
+                    // incorrectly because, the variable is inherited to children and we would malform the data
+                    // we need just to get operational root subApi...
+                        rootApi = mountPointApis[0],
+                        rootOperSubApi = rootApi.subApis.filter(function (sa) {
+                            return sa.pathTemplateString === 'yang-ext:mount/' && sa.storage === constants.DATA_STORE_OPERATIONAL;
+                        })[0];
+
+                    if (rootOperSubApi) {
+                        var rootConfigSubApi =  rootOperSubApi.clone(), // clone it and...
+                            firstConfigSubApiIndex = findFirstSubApiIndex(rootApi.subApis);
+                        // we need to find first index of config
+                        // subApi - because generating treeApis depends on order
+
+                        // set storage to config
+                        rootConfigSubApi.storage = constants.DATA_STORE_CONFIG;
+                        rootConfigSubApi.pathArray[0].name = constants.DATA_STORE_CONFIG;
+
+                        // and add it to rest of the apis
+                        rootApi.subApis.splice(firstConfigSubApiIndex, 0, rootConfigSubApi);
+                        rootConfigSubApi.parent = rootApi;
+                    }
+
+                    var mountPointTreeApis = YangUtilsService.generateApiTreeData(mountPointApis),
+                        pathItems = path.split('/');
+
+                    MountPointsConnectorService.updateMountPointApis(scope.selectedSubApi.pathArray, mountPointApis);
+
+                    // call initialization after necessary things are loaded
+                    controller.initMountPoint(mountPointTreeApis, mountPointApis, mpAugments, reqObj);
+
+                    scope.rootBroadcast(
+                        constants.YANGMAN_SET_MODULE_LIST_TITLE,
+                        pathItems[pathItems.length - 1] + ' [ ' + $filter('translate')(constants.YANGMAN_MOUNT_POINT) + ' ]'
+                    );
+
+                    controller.selectedPluginsButtons.push(
+                        MountPointsConnectorService.createCustomButton(constants.YANGMAN_CANCEL_MP, function (){
+                            return controller.selectedPlugin.label === constants.YANGMAN_CUST_MOUNT_POINTS;
+                        },
+                        function (){
+                            controller.unsetPluginFunctionality();
+                        })
+                    );
+
+                } else {
+                    $timeout(function (){
+                        controller.selectedPlugin = null;
+                        scope.rootBroadcast(constants.YANGMAN_SET_LOADING_BOX, false);
+                        scope.rootBroadcast(constants.YANGMAN_SHOW_TOAST, constants.YANGMAN_NO_MOUNT_POINT);
+                    }, 100);
+                }
+            }
+
+        }
+    }
+});
diff --git a/modules/yangman-resources/src/main/resources/yangman/services/requests.services.js b/modules/yangman-resources/src/main/resources/yangman/services/requests.services.js
new file mode 100644 (file)
index 0000000..cde859f
--- /dev/null
@@ -0,0 +1,341 @@
+define([
+    'app/yangman/models/historylist.model',
+    'app/yangman/models/collectionlist.model',
+    'app/yangman/models/history-request.model',
+], function (HistoryListModel, CollectionListModel, HistoryRequestModel) {
+    'use strict';
+
+    angular.module('app.yangman').service('RequestsService', RequestsService);
+
+    RequestsService.$inject = [
+        '$filter', 'PathUtilsService', 'ParametersService', 'ParsingJsonService', 'YangUtilsService',
+        'RequestBuilderService', 'constants',
+    ];
+
+    function RequestsService($filter, PathUtilsService, ParametersService, ParsingJsonService, YangUtilsService,
+                             RequestBuilderService, constants) {
+
+        var service = {};
+
+        service.applyParamsToObj = applyParamsToObj;
+        service.applyParamsToStr = applyParamsToStr;
+        service.clearUnnecessaryProperties = clearUnnecessaryProperties;
+        service.createEmptyCollectionList = createEmptyCollectionList;
+        service.createEmptyHistoryList = createEmptyHistoryList;
+        service.createHistoryRequestFromElement = createHistoryRequestFromElement;
+        service.createHistoryRequest = createHistoryRequest;
+        service.fillRequestByMethod = fillRequestByMethod;
+        service.fillRequestByViewType = fillRequestByViewType;
+        service.findIdentifierByParam = findIdentifierByParam;
+        service.scanDataParams = scanDataParams;
+        service.replaceStringInText = replaceStringInText;
+
+        /**
+         * Clear unnecesary properties for saving to collection
+         * @param request
+         */
+        function clearUnnecessaryProperties(request){
+            request.status = '';
+            request.responseStatus = null;
+            request.responseStatusText = null;
+            request.responseTime = null;
+
+            return request;
+        }
+
+        /**
+         * Find parametrized identifier in path array
+         * @param params
+         * @param pathElement
+         * @returns {*}
+         */
+        function findIdentifierByParam(params, pathElement){
+            var foundIdentifier = null;
+
+            if ( pathElement.hasIdentifier() ){
+                pathElement.identifiers.some(function (item){
+                    return params.list.some(function (param){
+                        var contained = item.value.indexOf('<<' + param.name + '>>') > -1;
+
+                        if ( contained ){
+                            foundIdentifier = item;
+                        }
+
+                        return contained;
+                    });
+                });
+            }
+
+            return foundIdentifier;
+        }
+
+        /**
+         * Get data for saving request depend on view type
+         * @param node
+         * @param viewType
+         * @param requestData
+         * @param dataType
+         * @param method
+         * @returns {*}
+         */
+        function fillRequestByViewType(node, viewType, requestData, dataType, method){
+            var setDataByViewType = {
+                form: function () {
+                    var data = {},
+                        emptyObject = method === constants.OPERATION_POST && dataType.toUpperCase() === constants.REQUEST_DATA_TYPE_RECEIVED && node.type !== constants.NODE_RPC;
+
+                    if ( !emptyObject ) {
+                        node.buildRequest(RequestBuilderService, data, node.module);
+                        data = checkNodeTypeData(node, data, dataType, requestData);
+                    }
+
+                    return data;
+                },
+                'req-data': function (){
+                    return requestData ? angular.fromJson(requestData) : {};
+                },
+            };
+
+            return setDataByViewType[viewType]();
+
+            /**
+             * Exceptions based on node type
+             * @param node
+             * @param data
+             * @param dataType
+             * @param requestData
+             * @returns {*}
+             */
+            function checkNodeTypeData(node, data, dataType, requestData){
+                var copyData = angular.copy(data),
+                    setDataByNodeType = {
+                        rpc: function (){
+
+                            if ( dataType.toUpperCase() === constants.REQUEST_DATA_TYPE_RECEIVED ) {
+                                copyData = requestData ? angular.fromJson(requestData) : {};
+                            }
+
+                            return copyData;
+                        },
+                        default: function () {
+                            return data;
+                        },
+                    };
+
+                return (setDataByNodeType[node.type] || setDataByNodeType.default)();
+            }
+        }
+
+        /**
+         * Fill history request data depend on selected method - saving to collection
+         * @param requestObj
+         * @param sentData
+         * @param receivedData
+         * @param method
+         */
+        function fillRequestByMethod(requestObj, sentData, receivedData, method, node, viewType){
+            var setDataByMethod = {
+                    GET: function (){
+                        return {
+                            sentData: {},
+                            receivedData: receivedData.reqData ? angular.fromJson(receivedData.reqData) : {},
+                        };
+                    },
+                    POST: function (){
+                        return {
+                            sentData: fillRequestByViewType(node, viewType, sentData.reqData, 'sent', method),
+                            receivedData: fillRequestByViewType(
+                                node, viewType, receivedData.reqData, constants.REQUEST_DATA_TYPE_RECEIVED, method
+                            ),
+                        };
+                    },
+                    PUT: function (){
+                        return {
+                            sentData: fillRequestByViewType(node, viewType, sentData.reqData, 'sent', method),
+                            receivedData: {},
+                        };
+                    },
+                    DELETE: function (){
+                        return {
+                            sentData: {},
+                            receivedData: {},
+                        };
+                    },
+                },
+                data = setDataByMethod[method]();
+
+            requestObj.setExecutionData(data.sentData, data.receivedData, '');
+        }
+
+        /**
+         * Scan used parameters in current line of codemirror
+         * @param {ParametersListModel} paramsObj - list of parameters to be searched for
+         * @param {string} lineString - line from current codemirror to be inspected
+         * @returns array of {ParameterModel}
+         */
+        function scanDataParams(paramsObj, lineString) {
+
+            var usedParamLabelArray = [];
+
+            var params = lineString ? lineString.match(/<<(?!<<)[a-zA-Z0-9]+>>/g) : null;
+
+            if ( params ) {
+                params
+                    .filter(onlyUnique)
+                    .forEach(function (param) {
+                        usedParamLabelArray.push(removeUnwantedChars(param));
+                    });
+            }
+
+            var returnedParamsList = paramsObj.list.filter( function (param){
+                var paramIndex = usedParamLabelArray.indexOf(param.name);
+
+                if ( paramIndex !== -1 ) {
+                    return usedParamLabelArray.splice(paramIndex, 1);
+                }
+                else {
+                    return false;
+                }
+            });
+
+            usedParamLabelArray.forEach(function (param){
+                returnedParamsList.push(ParametersService.createParameter({ name: param }));
+            });
+
+            return returnedParamsList;
+
+            /**
+             * remove chars greater then and less then from parameter definition
+             * @param val
+             * @returns {string}
+             */
+            function removeUnwantedChars(val){
+                var string = val.substring(2);
+                return string.substring(0, string.indexOf('>>'));
+            }
+
+            /**
+             * Filter function
+             * @param value
+             * @param index
+             * @param self
+             * @returns {boolean}
+             */
+            function onlyUnique(value, index, self) {
+                return self.indexOf(value) === index;
+            }
+        }
+
+        /**
+         * Replace all parameters with its values
+         * @param paramsObj
+         * @param str
+         * @returns {*}
+         */
+        function applyParamsToStr(paramsObj, str) {
+            if (paramsObj && paramsObj.hasOwnProperty('list')) {
+                paramsObj.list.forEach(function (param){
+                    str = service.replaceStringInText(str, '<<' + param.name + '>>', param.value);
+                });
+            }
+
+            return str;
+        }
+
+        /**
+         * Replace all parameters with its values
+         * @param paramsObj
+         * @param requestData
+         * @returns {*}
+         */
+        function applyParamsToObj(paramsObj, data) {
+            var dataStr = JSON.stringify(data);
+
+            dataStr = service.applyParamsToStr(paramsObj, dataStr);
+
+            return ParsingJsonService.parseJson(dataStr);
+        }
+
+        /**
+         * Service for replacing string in text
+         * @param text
+         * @param strToReplace
+         * @param newStr
+         * @returns {*}
+         */
+        function replaceStringInText(text, strToReplace, newStr) {
+            var replacedText = text;
+            if (text.indexOf(strToReplace) > -1) {
+                replacedText = text.split(strToReplace).join(newStr);
+            }
+            return replacedText;
+        }
+
+        /**
+         * Service for creating basic history object
+         * @param sentData
+         * @param receivedData
+         * @param path
+         * @param operation
+         * @param status
+         * @param name
+         * @param collection
+         * @returns {*}
+         * @param timestamp
+         */
+        function createHistoryRequest(sentData, receivedData, path, operation, status, name, collection, timestamp,
+                                      responseStatus, responseStatusText, responseTime) {
+            var result = new HistoryRequestModel(PathUtilsService, YangUtilsService, ParsingJsonService);
+
+            timestamp = timestamp || Date.now();
+
+            result.setData(sentData, receivedData, status, path, operation, name, collection, timestamp,
+                responseStatus, responseStatusText, responseTime);
+
+            return result;
+        }
+
+        /**
+         * Creating {HistoryRequest} from elem containing all necessary data
+         * @param {Object} elem
+         * @returns {*}
+         */
+        function createHistoryRequestFromElement(elem) {
+            if (!elem.hasOwnProperty('timestamp') || elem.timestamp === ''){
+                elem.timestamp = Date.now();
+            }
+
+            return service.createHistoryRequest(elem.sentData, elem.receivedData, elem.path, elem.method,
+                elem.status, elem.name, elem.collection, elem.timestamp, elem.responseStatus,
+                elem.responseStatusText, elem.responseTime
+            );
+        }
+
+        /**
+         * Service for creating empty collection list
+         * @param name
+         * @param getApiFunction
+         * @returns {CollectionList}
+         */
+        function createEmptyCollectionList(name){
+            var result = new CollectionListModel($filter, ParsingJsonService, service);
+            result.setName(name);
+            return result;
+        }
+
+        /**
+         * Service for creating empty history list
+         * @param name
+         * @returns {*}
+         */
+        function createEmptyHistoryList(name){
+            var result = new HistoryListModel($filter, ParsingJsonService, service);
+            result.setName(name);
+            return result;
+        }
+
+        return service;
+
+    }
+
+});
diff --git a/modules/yangman-resources/src/main/resources/yangman/services/time-tracking.services.js b/modules/yangman-resources/src/main/resources/yangman/services/time-tracking.services.js
new file mode 100644 (file)
index 0000000..fcb9c59
--- /dev/null
@@ -0,0 +1,23 @@
+define([], function () {
+    'use strict';
+
+    angular.module('app.yangman').service('TimeTrackingService', TimeTrackingService);
+
+    function TimeTrackingService(){
+        var service = {
+                startTimer: startTimer,
+                returnTime: returnTime,
+            },
+            timeStarted = 0;
+        return service;
+
+        function startTimer(){
+            timeStarted = new Date().getTime();
+        }
+
+        function returnTime(){
+            return new Date().getTime() - timeStarted;
+        }
+    }
+
+});
diff --git a/modules/yangman-resources/src/main/resources/yangman/services/yangman-design.services.js b/modules/yangman-resources/src/main/resources/yangman/services/yangman-design.services.js
new file mode 100644 (file)
index 0000000..cd2de28
--- /dev/null
@@ -0,0 +1,125 @@
+define([], function () {
+    'use strict';
+
+    angular.module('app.yangman').service('YangmanDesignService', YangmanDesignService);
+
+    YangmanDesignService.$inject = ['$timeout'];
+
+    function YangmanDesignService($timeout){
+
+        var service = {
+            disableMdMenuItem: disableMdMenuItem,
+            enableMdMenuItem: enableMdMenuItem,
+            hideMainMenu: hideMainMenu,
+            setDraggableLeftPanel: setDraggableLeftPanel,
+            setJsonSplitter: setJsonSplitter,
+            setModuleDetailHeight: setModuleDetailHeight,
+        };
+
+        return service;
+
+
+        /**
+         * Get button dom element from mdMenuItem ng-click $event
+         * @param event
+         */
+        function getButtElemFromMdMenuItemEvent(event) {
+            var elemSelAttempt = angular.element(event.toElement.parentElement).find('.md-button'),
+                result = null;
+
+            // if mdMenuItem was clicked, it should contain only one button
+            if (elemSelAttempt.length === 1) {
+                result = elemSelAttempt[0];
+            }
+            // if span or icon inside button was clicked, button element should be its parent
+            else if (elemSelAttempt.length === 0) {
+                result = angular.element(event.toElement.parentElement)[0];
+            }
+
+            if (result.nodeName === 'BUTTON') {
+                return result;
+            }
+            else {
+                return null;
+            }
+        }
+
+        /**
+         * Disable md menu item on which was clicked in event
+         * Use to prevent accidentally doubleclicking or enterhitting
+         * @param event - $event object from ng-click
+         */
+        function disableMdMenuItem(event) {
+            var buttElem = getButtElemFromMdMenuItemEvent(event);
+            if (buttElem) {
+                buttElem.disabled = true;
+            }
+        }
+
+
+        /**
+         * Disable md menu item on which was clicked in event
+         * Use to prevent accidentally doubleclicking or enterhitting
+         * @param event - $event object from ng-click
+         */
+        function enableMdMenuItem(event) {
+            var buttElem = getButtElemFromMdMenuItemEvent(event);
+            if (buttElem) {
+                buttElem.disabled = false;
+            }
+        }
+
+
+        /**
+         * Hide main menu
+         */
+        function hideMainMenu(){
+            angular.element('#wrapper').addClass('toggled');
+        }
+
+        /**
+         * Sets Draggable Left Side
+         * #left-panel
+         */
+        function setDraggableLeftPanel(){
+            if (localStorage.getItem('yangman__left-panel-width') !== null) {
+                angular.element('#left-panel').width(localStorage.getItem('yangman__left-panel-width'));
+            }
+
+            angular.element('.ym-resizable-e').resizable({
+                handles: 'e',
+                minWidth: 300,
+                stop: function(event, ui) {
+                    if (typeof(Storage) !== 'undefined') {
+                        localStorage.setItem('yangman__left-panel-width', ui.size.width);
+                    }
+                },
+                resize: function() {
+                    setModuleDetailHeight();
+                }
+            });
+        }
+
+        function setJsonSplitter(cbk){
+            $timeout(function () {
+                angular.element('.ym-resizable-s').resizable({
+                    handles: 's',
+                    minHeight: 200,
+                    stop: function(event, ui) {
+                        cbk();
+                    }
+                });
+            });
+        }
+
+        /**
+         * Set module detail height
+         * .yangmanModule__module-detail .tabs
+         */
+        function setModuleDetailHeight() {
+            var height = 'calc(100% - ' + angular.element('.yangmanModule__module-detail h4').outerHeight(true) + 'px)';
+            angular.element('.yangmanModule__module-detail .tabs').css({ height: height });
+        }
+
+    }
+});
diff --git a/modules/yangman-resources/src/main/resources/yangman/services/yangman.services.js b/modules/yangman-resources/src/main/resources/yangman/services/yangman.services.js
new file mode 100644 (file)
index 0000000..6ff2979
--- /dev/null
@@ -0,0 +1,380 @@
+define([], function () {
+    'use strict';
+
+    angular.module('app.yangman').service('YangmanService', YangmanService);
+
+    YangmanService.$inject = [
+        'RequestBuilderService',
+        'YangUtilsService',
+        'YangUtilsRestangularService',
+        'ENV',
+        'ParsingJsonService',
+        'RequestsService',
+        'PathUtilsService',
+        'constants',
+    ];
+
+    function YangmanService(
+        RequestBuilderService,
+        YangUtilsService,
+        YangUtilsRestangularService,
+        ENV,
+        ParsingJsonService,
+        RequestsService,
+        PathUtilsService,
+        constants
+    ){
+        var service = {
+            cutUrl: cutUrl,
+            checkRpcReceivedData: checkRpcReceivedData,
+            executeRequestOperation: executeRequestOperation,
+            fillNodeFromResponse: fillNodeFromResponse,
+            getDataStoreIndex: getDataStoreIndex,
+            handleNodeIdentifier: handleNodeIdentifier,
+            prepareAllRequestData: prepareAllRequestData,
+            prepareReceivedData: prepareReceivedData,
+            putIntoObj: putIntoObj,
+            setSrcDataByDataType: setSrcDataByDataType,
+            validateFile: validateFile,
+        };
+
+        return service;
+
+        /**
+         * Handle param continuum between header path array and node data
+         * @param parametersList
+         * @param selectedSubApi
+         * @param node
+         */
+        function handleNodeIdentifier(parametersList, selectedSubApi, node){
+            var identifier = RequestsService.findIdentifierByParam(
+                parametersList, selectedSubApi.pathArray[selectedSubApi.pathArray.length - 1]
+            );
+
+            if ( identifier ){
+                PathUtilsService.fillListNode(node, identifier.label, identifier.value);
+            }
+        }
+
+        /**
+         * Put data to output container if root node is rpc
+         * @param data
+         * @param node
+         * @returns {*}
+         */
+        function checkRpcReceivedData(data, node){
+            return node.type === constants.NODE_RPC ? cutData(data) : data;
+
+            function cutData(data){
+                return {
+                    output: data[node.label].output,
+                };
+            }
+        }
+
+        /**
+         * Put source object into destination object by source properties
+         * @param sourceObj
+         * @param destinationObj
+         */
+        function putIntoObj(sourceObj, destinationObj, containter){
+            if ( sourceObj ) {
+                Object.keys(sourceObj).forEach(function(prop){
+                    destinationObj[containter] = destinationObj[containter] ? destinationObj[containter] : {};
+                    destinationObj[containter][prop] = sourceObj[prop];
+                });
+            }
+        }
+
+        /**
+         * Prepare request date before filling into node depends on method and node type
+         * @param node
+         * @param method
+         * @param rData
+         * @param sData
+         * @param outputType
+         * @returns {*}
+         */
+        function prepareReceivedData(node, method, rData, sData, outputType){
+            var prepareType = {
+                rpc: function (){
+
+                    if ( outputType === constants.DISPLAY_TYPE_FORM ){
+                        var dObj = {};
+
+                        if ( !sData ) {
+                            sData = {};
+                            sData[node.label] = {};
+                        }
+
+                        putIntoObj(rData, dObj, node.label);
+                        putIntoObj(sData[node.label] ? sData[node.label] : sData, dObj, node.label);
+                        return dObj;
+                    } else {
+                        return rData;
+                    }
+                },
+                default: function (){
+                    var methodType = {
+                        GET: function () {
+                            if ( node ){
+                                node.clear();
+                            }
+                            return rData;
+                        },
+                        DELETE: function () {
+                            if ( node ) {
+                                node.clear();
+                            }
+                            return {};
+                        },
+                        DEFAULT: function () {
+                            return rData;
+                        },
+                    };
+
+                    return (methodType[method] || methodType.DEFAULT)();
+                },
+            };
+
+            return (prepareType[node ? node.type : 'default'] || prepareType.default)();
+        }
+
+        /**
+         * Validating collection import file
+         * @param data
+         * @param checkArray
+         * @returns {*}
+         */
+        function validateFile(data, checkArray){
+            try {
+                var obj = ParsingJsonService.parseJson(data);
+
+                return obj && obj.every(function (el){
+                    return checkArray.every(function (arr){
+                        return el.hasOwnProperty(arr);
+                    });
+                });
+            } catch (e) {
+                return e;
+            }
+        }
+
+        /**
+         * Return index of selected datastore in list
+         * @param list
+         * @param dataStore
+         * @returns {*}
+         */
+        function getDataStoreIndex(list, dataStore){
+            var rIndex = null,
+                result = list.some(function (item, index) {
+                    rIndex = index;
+                    return item.label === dataStore;
+                });
+
+            return result ? rIndex : null;
+        }
+
+        /**
+         * Apply all parametrized values into request (data, url, pathArray)
+         * @param allPreparedData
+         * @param params
+         * @param selSubApiCopy
+         * @param requestUrl
+         */
+        function setParametrizedData(allPreparedData, params, selSubApiCopy, requestUrl){
+            allPreparedData.reqFullUrl = RequestsService.applyParamsToStr(params, requestUrl);
+
+            // apply parametrized value into request data in string form
+            allPreparedData.reqString =
+                selSubApiCopy ? RequestsService.applyParamsToStr(params, selSubApiCopy.buildApiRequestString()) : '';
+
+            if ( !angular.equals(allPreparedData.reqFullUrl, requestUrl) && selSubApiCopy ){
+                // fill parametrized data into path array
+                PathUtilsService.fillPath(selSubApiCopy.pathArray, allPreparedData.reqFullUrl);
+            }
+
+            allPreparedData.reqData = RequestsService.applyParamsToObj(params, allPreparedData.srcData);
+        }
+
+        /**
+         * Set source data into request object based on shown data type
+         * @param allPreparedData
+         * @param node
+         * @param requestData
+         * @param dataType
+         */
+        function setSrcDataByDataType(allPreparedData, node, requestData, dataType){
+            if ( dataType === constants.DISPLAY_TYPE_FORM && node){
+                node.buildRequest(RequestBuilderService, requestData, node.module);
+                allPreparedData.srcData = angular.copy(requestData);
+            }
+            else {
+                allPreparedData.srcData = requestData;
+            }
+        }
+
+        /**
+         * Prepare all necessary data for executing or saving request
+         * @param selectedApi
+         * @param selectedSubApi
+         * @param operation
+         * @param node
+         * @param dataType
+         * @param requestUrl
+         * @param requestData
+         * @param params
+         * @returns {{customRestangular: null, headers: {}, operation: string, reqString: string, reqHeaders: {},
+         *          reqData: {}}}
+         */
+        function prepareAllRequestData(selectedApi, selectedSubApi, operation, node, dataType, requestUrl, requestData,
+                                       params) {
+            var allPreparedData = {
+                    customRestangular: null,
+                    headers: {},
+                    operation: '',
+                    reqString: '',
+                    reqHeaders: {},
+                    reqData: '',
+                    srcData: '',
+                    reqFullUrl: '',
+                },
+                selSubApiCopy = angular.copy(selectedSubApi);
+
+            setSrcDataByDataType(allPreparedData, node, requestData, dataType);
+            setParametrizedData(allPreparedData, params, selSubApiCopy, requestUrl);
+
+            // prepare req data
+            if (operation === constants.OPERATION_GET || operation === constants.OPERATION_DELETE){
+                allPreparedData.srcData = null;
+                allPreparedData.reqData = null;
+            }
+            else if ( operation === constants.OPERATION_POST ){
+
+                if ( selSubApiCopy ) {
+                    allPreparedData.reqData = YangUtilsService.postRequestData(
+                        allPreparedData.reqData,
+                        allPreparedData.reqString,
+                        selSubApiCopy
+                    );
+                }
+            }
+
+            // set correct host into restangular based on shown data type and prepare data
+            if ( dataType === constants.DISPLAY_TYPE_REQ_DATA ){
+                var parser = locationHelper(allPreparedData.reqFullUrl, ['pathname', 'origin']),
+                    raParam = '';
+
+                YangUtilsRestangularService.setBaseUrl(parser.origin);
+                allPreparedData.reqString = parser.pathname.slice(1).split('/');
+                raParam = allPreparedData.reqString.shift();
+                allPreparedData.reqString = allPreparedData.reqString.join('/');
+
+                allPreparedData.customRestangular = YangUtilsRestangularService.one(raParam);
+
+            } else {
+
+                YangUtilsRestangularService.setBaseUrl(ENV.getBaseURL('MD_SAL'));
+                allPreparedData.customRestangular  = YangUtilsRestangularService.one('restconf');
+
+                if ( node ) {
+                    allPreparedData.headers = YangUtilsService.prepareHeaders(allPreparedData.reqData);
+                }
+            }
+
+            allPreparedData.operation = YangUtilsService.prepareOperation(operation);
+            return allPreparedData;
+        }
+
+        function cutUrl(url){
+            return url.indexOf('restconf') > -1 ? url.split('restconf')[1].substring(1) : url;
+        }
+
+        /**
+         * Execute request built from this data
+         * @param selectedApi
+         * @param selectedSubApi
+         * @param operation
+         * @param node
+         * @param dataType
+         * @param requestUrl
+         * @param requestData
+         * @param successCbk
+         * @param errorCbk
+         * @param params
+         */
+        function executeRequestOperation(selectedApi, selectedSubApi, operation, node, dataType, requestUrl,
+                                         requestData, params, successCbk, errorCbk) {
+
+            YangUtilsRestangularService.setFullResponse(true);
+
+            // prepare all necessary data
+            var allPreparedData = prepareAllRequestData(selectedApi, selectedSubApi, operation, node, dataType,
+                requestUrl, requestData, params);
+
+            // executing operation
+            allPreparedData.customRestangular.customOperation(
+                allPreparedData.operation.toLowerCase(),
+                allPreparedData.reqString,
+                null,
+                allPreparedData.headers,
+                allPreparedData.reqData
+            )
+            .then(
+                function (response) {
+                    (successCbk || angular.noop)(finishExecuting(response), response);
+                },
+                function (response) {
+                    (errorCbk || angular.noop)(finishExecuting(response), response);
+                }
+            );
+
+            function finishExecuting(response){
+
+                return {
+                    status: response.status,
+                    statusText: response.statusText,
+                    time: null,
+                    requestData: allPreparedData.reqData,
+                    requestSrcData: allPreparedData.srcData,
+                };
+            }
+        }
+
+        /**
+         * Method for parsing path to additional properties based on JS LOCATION
+         * @param path
+         * @param properties
+         * @returns {{}}
+         */
+        function locationHelper(path, properties){
+            var parser = document.createElement('a'),
+                obj = {};
+
+            parser.href = path;
+
+            properties.forEach(function (prop) {
+                obj[prop] = parser[prop];
+            });
+
+            return obj;
+        }
+
+        /**
+         * Fill node values from response
+         * @param node
+         * @param data
+         */
+        function fillNodeFromResponse(node, data){
+            var props = data ? Object.getOwnPropertyNames(data) : [];
+
+            // fill each property - needed for root mountpoint node,
+            // in other cases there should be only one property anyway
+            props.forEach(function (p) {
+                node.fill(p, data[p]);
+            });
+        }
+    }
+
+});
diff --git a/modules/yangman-resources/src/main/resources/yangman/views/directives/abn-tree.tpl.html b/modules/yangman-resources/src/main/resources/yangman/views/directives/abn-tree.tpl.html
new file mode 100644 (file)
index 0000000..257206f
--- /dev/null
@@ -0,0 +1,11 @@
+<md-list class="directive__abn-tree">
+        <md-list-item ng-repeat="row in tree_rows | filter:{visible:true} track by row.branch.uid"
+                      ng-class="'level-' + {{ row.level }} + (row.branch.selected ? ' active':'')"
+                      ng-click="user_clicks_branch(row.branch)"
+                      ng-init="(_dataCollection = []).length = row.level;">
+            <span ng-repeat="i in _dataCollection track by $index" ng-class="{'empty-box' : $index !== 0}"></span>
+            <md-icon md-font-set="material-icons" class="pointer" ng-click="row.branch.expanded = !row.branch.expanded">{{row.tree_icon}}</md-icon>
+            <span flex class="indented tree-label">{{ row.label }} {{ row.branch.identifier }}</span>
+        </md-list-item>
+</md-list>
+
diff --git a/modules/yangman-resources/src/main/resources/yangman/views/directives/yang-form-menu.tpl.html b/modules/yangman-resources/src/main/resources/yangman/views/directives/yang-form-menu.tpl.html
new file mode 100644 (file)
index 0000000..129fffe
--- /dev/null
@@ -0,0 +1,94 @@
+<div ng-if="isActionMenu()" class="menu-container md-menu">
+    <!-- Close menu (click catcher) -->
+    <div ng-show="isActive">
+        <md-backdrop ng-click="closeMenu()" class="md-menu-backdrop md-click-catcher" style="position: fixed;"></md-backdrop>
+    </div>
+    <!-- open menu button -->
+    <md-button class="md-icon-button" ng-click="openMenu(); hideInfoBox();">
+        <md-icon md-font-set="material-icons">reorder</md-icon>
+    </md-button>
+
+    <!-- Menu content -->
+    <div class="yang-menu-content md-menu-content" ng-show="isActive">
+        <h5 class="title">
+            {{ 'YANGMAN_YANG_MENU' | translate }}
+            <md-icon md-font-set="material-icons">reorder</md-icon>
+        </h5>
+        <md-divider></md-divider>
+
+        <!-- add list item -->
+        <div class="yang-menu-item md-menu-item" ng-if="addListItem">
+            <md-button ng-click="addListItemFunc(); closeMenu();">
+                <md-icon md-font-set="material-icons">library_add</md-icon>
+                <span md-menu-align-target>{{'YANGMAN_ADD_LIST_ITEM' | translate}}</span>
+            </md-button>
+        </div>
+
+        <!-- show items list -->
+        <div class="yang-menu-item md-menu-item" ng-if="yangList && node.actElemStructure">
+            <md-button ng-click="switchSection('items'); setItemList();">
+                <md-icon md-font-set="material-icons">list</md-icon>
+                <span md-menu-align-target>{{'YANGMAN_SHOW_LIST_ITEM' | translate}}</span>
+            </md-button>
+        </div>
+
+        <!-- augmentations menu item -->
+        <div class="yang-menu-item md-menu-item" ng-if="node.augmentionGroups.length">
+            <md-button ng-click="switchSection('augmentations')">
+                <md-icon md-font-set="material-icons">brightness_auto</md-icon>
+                <span md-menu-align-target>{{'YANGMAN_AUGMENTATIONS' | translate}}</span>
+            </md-button>
+        </div>
+
+        <!-- info box -->
+        <div id="infoBox" class="md-whiteframe-z2 info-box" ng-show="infoBox" ng-switch="infoBoxSection">
+            <div ng-switch-when="augmentations">
+                <md-list flex>
+                    <md-list-item ng-repeat="augmentation in node.augmentionGroups">
+                        <md-switch ng-model="augmentations.getAugmentation(node, augmentation).expanded"
+                                   aria-label="{{augmentation}}"
+                                   md-prevent-menu-close>
+                            {{augmentation}}
+                        </md-switch>
+                    </md-list-item>
+                </md-list>
+            </div>
+
+            <!-- yang list items -->
+            <div ng-switch-when="items">
+                <md-list>
+                    <md-list-item ng-repeat="_ in node.listData" class="no-wrap">
+                        <!-- icon -->
+                        <md-icon md-font-set="material-icons">
+                            {{ [yangList.currentDisplayIndex, yangList.currentDisplayIndex + 1, yangList.currentDisplayIndex - 1].indexOf($index) !== -1 ? 'remove_red_eye' : ''}}
+                        </md-icon>
+
+                        <!-- title -->
+                        <p ng-class="{'active' : node.actElemIndex === $index}"
+                           class="pointer"
+                           ng-click="node.changeActElementData($index)">
+                            {{yangForm.getNodeName(node.localeLabel, node.label)}}&nbsp;{{node.createListName($index) || '[' + $index + ']'}}
+                        </p>
+
+                        <!-- duplicated key -->
+                        <md-icon md-font-set="material-icons" ng-show="node.doubleKeyIndexes.indexOf($index) > -1">
+                            <md-tooltip md-direction="top">{{ 'YANGMAN_LIST_INDEX_DUPLICATE' | translate }}</md-tooltip>
+                            error_outline
+                        </md-icon>
+
+                        <!-- remove button -->
+                        <md-icon md-font-set="material-icons"
+                                 class="pointer"
+                                 ng-if="addListItem"
+                                 ng-click="yangList.removeListElem($index)">
+                            <md-tooltip md-direction="top">{{ 'YANGMAN_LIST_DELETE_ITEM' | translate }}</md-tooltip>
+                            remove_circle_outline
+                        </md-icon>
+
+                        <md-ink-bar ng-if="node.actElemIndex === $index" class="custom"></md-ink-bar>
+                    </md-list-item>
+                </md-list>
+            </div>
+        </div>
+    </div>
+</div>
diff --git a/modules/yangman-resources/src/main/resources/yangman/views/directives/ym-info-box.tpl.html b/modules/yangman-resources/src/main/resources/yangman/views/directives/ym-info-box.tpl.html
new file mode 100644 (file)
index 0000000..2adf384
--- /dev/null
@@ -0,0 +1,20 @@
+<span ng-mouseenter="executeInfoBox(true)" ng-mouseleave="executeInfoBox(false)" class="info-box-container__hover-wrapper">
+    <span ng-transclude></span>
+
+    <div class="md-whiteframe-z2 info-box" ng-show="showBoxCheck()">
+        <div class="info-box__padding">
+            <!-- key -->
+            <span ng-show="node.isKey()">
+                {{'Key for "' + node.parent.label + '"'}}
+                <md-menu-divider ng-show="dividerCheck(true)"></md-menu-divider>
+            </span>
+            <!-- augment -->
+            <span ng-show="node.augmentationId">
+                {{ 'YANGMAN_IS_AUGMENT' | translate }} <i>{{node.type}}</i> "{{ node.augmentationId }}"
+                <md-menu-divider ng-show="dividerCheck()"></md-menu-divider>
+            </span>
+            <!-- description -->
+            <span ng-show="description.length">{{description}}</span>
+        </div>
+    </div>
+</span>
diff --git a/modules/yangman-resources/src/main/resources/yangman/views/index.tpl.html b/modules/yangman-resources/src/main/resources/yangman/views/index.tpl.html
new file mode 100644 (file)
index 0000000..ab6be16
--- /dev/null
@@ -0,0 +1,48 @@
+<section class="yangmanModule" id="yangmanModule" layout="row">
+
+    <!-- LEFT SIDE -->
+    <md-content layout="column" style="width: 400px; height: 100%;" class="yangmanModule__left-panel ym-resizable-e" id="left-panel">
+        <!-- module arrow button -->
+        <md-icon md-font-set="material-icons "
+                 class="arrow-switcher"
+                 ng-click="main.toggleLeftPanel(); main.initModuleDetailHeight();"
+                 ng-class="{'arrow-switcher__left' : main.leftPanelTab === 0}"
+                 ng-show="selectedDatastore"> play_arrow </md-icon>
+                 <!--ng-show="!main.selectedMainTab && selectedDatastore"> play_arrow </md-icon>-->
+        <!-- content -->
+        <md-tabs md-border-bottom md-selected="main.leftPanelTab" class="yangmanModule__left-panel__detail-list-tabs-container">
+            <md-tab label="models tree">
+                <md-content>
+
+                    <!-- MODULES HISTORY COLLECTION TABS -->
+                    <md-tabs class="yangmanModule__mhc-tabs inline-tabs" md-no-pagination md-dynamic-height md-stretch-tabs="always">
+                        <!-- Modules tab -->
+                        <md-tab label="{{'YANGMAN_MODULES' | translate}}" md-on-select="main.switchedTab(0)">
+                            <div ng-include src="globalViewPath + 'leftpanel/modules-tab.tpl.html'" class="h100"></div>
+                        </md-tab>
+                        <!-- History tab -->
+                        <md-tab label="{{'YANGMAN_HISTORY' | translate}}" md-on-select="main.switchedTab(1)">
+                            <div ng-include src="globalViewPath + 'leftpanel/history-tab.tpl.html'" class="historyTab"></div>
+                        </md-tab>
+                        <!-- Collection tab -->
+                        <md-tab label="{{'YANGMAN_COLLECTIONS' | translate}}" md-on-select="main.switchedTab(2)">
+                            <div ng-include src="globalViewPath + 'leftpanel/collections-tab.tpl.html'" class="collectionsTab"></div>
+                        </md-tab>
+                    </md-tabs>
+                </md-content>
+            </md-tab>
+
+            <!-- MODULE TREE DETAIL -->
+            <md-tab label="model detail" md-on-select="main.initModuleDetailHeight()">
+                <md-content class="yangmanModule__module-detail">
+                    <div ng-include src="globalViewPath + 'leftpanel/module-detail.tpl.html'"></div>
+                </md-content>
+            </md-tab>
+        </md-tabs>
+    </md-content>
+
+    <!-- RIGHT SIDE -->
+    <md-content layout="column" flex
+                class="md-whiteframe-3dp md-padding yangmanModule__right-panel"
+                ng-include src="globalViewPath + 'rightpanel/detail.tpl.html'"></md-content>
+</section>
diff --git a/modules/yangman-resources/src/main/resources/yangman/views/leftpanel/collections-tab.tpl.html b/modules/yangman-resources/src/main/resources/yangman/views/leftpanel/collections-tab.tpl.html
new file mode 100644 (file)
index 0000000..b8d7a9e
--- /dev/null
@@ -0,0 +1,222 @@
+<md-list class="yangmanModule__requests-list__collections-list"
+         ng-cloak
+         ng-controller="RequestsListCtrl as reqList"
+         ng-init="reqList.init('collections')">
+
+    <md-content class="searchBox yangmanModule__left-panel__search" layout="row">
+
+        <!-- searching -->
+        <md-input-container layout="row" md-no-float class="modules-list-search" flex>
+            <!-- search icon, form, clear button -->
+            <md-icon class="material-icons">search</md-icon>
+            <input class="ng-pristine ng-valid ng-touched"
+                   type="text"
+                   flex
+                   placeholder="{{'YANGMAN_SEARCH' | translate}}"
+                   ng-model="reqList.search"
+                   aria-invalid="false" />
+            <md-button aria-label="{{'YANGMAN_CLEAR_SEARCH'| translate}}" flex="none"
+                       ng-click="reqList.clearFilter()"
+                       ng-if="reqList.search">
+                <md-icon class="material-icons clickable">
+                    close
+                </md-icon>
+                <md-tooltip md-direction="bottom">{{'YANGMAN_CLEAR_SEARCH'| translate}}</md-tooltip>
+            </md-button>
+            <!-- /search icon, form, clear button -->
+        </md-input-container>
+
+        <!-- sorting -->
+        <span class="collection-button-container">
+            <md-button  ng-click="reqList.toggleCollectionsSort()"
+                        ng-disabled="reqList.collectionList.collections.length <= 1">
+                <md-icon class="material-icons clickable" > sort</md-icon>
+            </md-button>
+            <md-tooltip md-direction="bottom">
+                {{ ( reqList.collectionsSortAsc ? 'YANGMAN_SORT_COLLECTIONS_DESC' : 'YANGMAN_SORT_COLLECTIONS_ASC' )| translate}}
+            </md-tooltip>
+        </span>
+        <!-- /sorting -->
+
+        <!-- save -->
+        <span class="collection-button-container">
+            <md-button  ng-click="reqList.showDgSaveReq($event)"
+                        ng-disabled="reqList.mainList.getSelectedItems(reqList.filterCollReq).length === 0">
+                <md-icon class="material-icons clickable">
+                    save
+                </md-icon>
+            </md-button>
+            <md-tooltip md-direction="bottom">{{'YANGMAN_REQS_SAVE_TO_COL'| translate}}</md-tooltip>
+        </span>
+        <!-- /save -->
+
+        <!-- importing -->
+        <span class="collection-button-container">
+            <input type="file" accept=".json" id="importCollection" on-read-file="reqList.readCollectionFromFile($fileContent)">
+            <md-button>
+                <label for="importCollection">
+                    <md-icon class="material-icons clickable" >
+                        file_upload
+                    </md-icon>
+                </label>
+            </md-button>
+            <md-tooltip md-direction="bottom">{{'YANGMAN_IMPORT_COLLECTION'| translate}}</md-tooltip>
+        </span>
+        <!-- /importing -->
+
+        <md-menu layout-align="center start">
+            <md-button ng-disabled="!reqList.mainList.list.length" aria-label="menu"  ng-click="$mdOpenMenu()">
+                <md-icon class="material-icons clickable"> delete</md-icon>
+                <md-tooltip md-direction="bottom">{{'YANGMAN_DELETE_OPTIONS' | translate}}</md-tooltip>
+            </md-button>
+            <md-menu-content>
+                <!-- delete selected -->
+                <md-menu-item>
+                    <md-button aria-label="{{'YANGMAN_REQS_DELETE'| translate}}"
+                               ng-click="reqList.showDgDeleteRequests($event)"
+                               ng-disabled="reqList.mainList.getSelectedItems(reqList.filterCollReq).length === 0">
+                        <md-icon class="material-icons clickable">
+                            delete
+                        </md-icon>
+                        {{'YANGMAN_REQS_DELETE'| translate}}
+                    </md-button>
+                </md-menu-item>
+                <!-- / delete selected -->
+                <!-- clear collections -->
+                <md-menu-item>
+                    <md-button aria-label="{{'YANGMAN_DELETE_COLLECTIONS' | translate}}"
+                               ng-click="reqList.clearCollectionList($event)">
+                        <md-icon class="material-icons clickable">
+                            delete_forever
+                        </md-icon>
+                        {{'YANGMAN_DELETE_COLLECTIONS' | translate}}
+                    </md-button>
+                </md-menu-item>
+                <!-- / clear history -->
+            </md-menu-content>
+        </md-menu>
+        <!-- / menu for deleting and clearing -->
+
+        <!-- menu for selecting and deselecting-->
+        <md-menu layout-align="center start">
+            <md-button ng-disabled="( !reqList.mainList.list.length)" aria-label="menu"  ng-click="$mdOpenMenu()">
+                <md-icon class="material-icons clickable">
+                    playlist_add_check
+                </md-icon>
+                <md-tooltip md-direction="bottom">{{'YANGMAN_SELECT_OPTIONS' | translate}}</md-tooltip>
+            </md-button>
+            <md-menu-content>
+                <!-- select all -->
+                <md-menu-item>
+                    <md-button aria-label="{{'YANGMAN_SELECT_ALL' | translate}}"
+                               ng-click="reqList.selectAllFilteredRequests()">
+                        <md-icon class="material-icons clickable">
+                            done
+                        </md-icon>
+                        {{'YANGMAN_SELECT_ALL' | translate}}
+                    </md-button>
+                </md-menu-item>
+                <!-- /select all -->
+                <!-- deselect all -->
+                <md-menu-item>
+                    <md-button aria-label="{{'YANGMAN_DESELECT_ALL' | translate}}"
+                               ng-click="reqList.deselectAllFilteredRequests()"
+                               ng-disabled="reqList.mainList.getSelectedItems(reqList.filterCollReq).length === 0">
+                        <md-icon class="material-icons clickable">
+                            close
+                        </md-icon>
+                        {{'YANGMAN_DESELECT_ALL' | translate}}
+                    </md-button>
+                </md-menu-item>
+                <!-- / deselect all -->
+            </md-menu-content>
+        </md-menu>
+        <!-- / menu for selecting and deselecting -->
+    </md-content>
+
+    <md-divider></md-divider>
+
+    <!-- collection list -->
+    <md-content class="scrollableY">
+
+        <div ng-repeat="collection in reqList.mainList.collections | filter: reqList.filterCol | orderBy: (reqList.collectionsSortAsc ? '' : '-')+'name'">
+
+            <div layout="row">
+
+                <md-list-item class="yangmanModule__requests-list__collection"
+                              flex
+                              ng-class="{'expanded' : collection.expanded, 'selected': collection.expanded}"
+                              ng-click="collection.toggleExpanded()">
+
+                    <div layout="row">
+                        <md-icon md-font-set="material-icons" class="top-icon">
+                            folder_open
+                        </md-icon>
+                        <div layout="column">
+
+                            <p flex>
+                            <span md-highlight-text="reqList.search" md-highlight-flags="i">
+                                {{collection.name}}
+                            </span><br />
+                            <span class="desc">
+                                <span class="desc" ng-if="reqList.search && !reqList.filterColName(collection)">{{'YANGMAN_MATCHING'| translate}} {{reqList.colMatchingReqsCount(collection)}} / </span>
+                                {{collection.data.length}} {{(collection.data.length>1 ? 'YANGMAN_COLLECTION_REQUESTS' : 'YANGMAN_COLLECTION_REQUEST')| translate}}
+                            </span>
+                            </p>
+                        </div>
+                    </div>
+
+                </md-list-item>
+                <md-menu class="yangmanModule__requests-list__group__collectionMenu"
+                         md-offset="35 15"
+                         layout-align="center start">
+                    <md-button aria-label="menu" class="md-primary" ng-click="$mdOpenMenu()">
+                        <i class="material-icons">menu</i>
+                    </md-button>
+                    <md-menu-content class="reqMenu">
+                        <md-menu-item>
+                            <md-button aria-label="Duplicate collection"
+                                       ng-click="reqList.showDgEditCollection($event, collection, false)">
+                                <i class="material-icons">mode_edit</i>
+                                {{'YANGMAN_COLLECTION_EDIT'| translate}}
+                            </md-button>
+                        </md-menu-item>
+                        <md-menu-item>
+                            <md-button aria-label="{{'YANGMAN_COLLECTION_DUPLICATE'| translate}}"
+                                       ng-click="reqList.showDgEditCollection($event, collection, true)">
+                                <i class="material-icons">control_point_duplicate</i>
+                                {{'YANGMAN_COLLECTION_DUPLICATE'| translate}}
+                            </md-button>
+                        </md-menu-item>
+                        <md-menu-item>
+                            <md-button aria-label="{{'YANGMAN_COLLECTION_DOWNLOAD'| translate}}"
+                                       ng-click="reqList.downloadCollection(collection)">
+                                <i class="material-icons">file_download</i>
+                                {{'YANGMAN_COLLECTION_DOWNLOAD'| translate}}
+                            </md-button>
+                        </md-menu-item>
+                        <md-menu-item>
+                            <md-button aria-label="{{'YANGMAN_COLLECTION_DELETE'| translate}}"
+                                       ng-click="reqList.showDgDeleteCollection($event, collection)">
+                                <i class="material-icons">delete</i>
+                                {{'YANGMAN_COLLECTION_DELETE'| translate}}
+                            </md-button>
+                        </md-menu-item>
+                    </md-menu-content>
+                </md-menu>
+            </div>
+
+
+            <md-list ng-show="collection.expanded" class="yangmanModule__requests-list__collection__requests">
+                <div ng-repeat="request in collection.data | filter: reqList.filterReq"
+                     layout="row"
+                     class="yangmanModule__requests-list__item-container"
+                     ng-include src="globalViewPath + 'leftpanel/request-item.tpl.html'">
+                </div>
+            </md-list>
+            <md-divider></md-divider>
+
+        </div>
+    </md-content>
+
+</md-list>
diff --git a/modules/yangman-resources/src/main/resources/yangman/views/leftpanel/edit-collection-dialog.tpl.html b/modules/yangman-resources/src/main/resources/yangman/views/leftpanel/edit-collection-dialog.tpl.html
new file mode 100644 (file)
index 0000000..595f750
--- /dev/null
@@ -0,0 +1,37 @@
+<md-dialog aria-label="{{'YANGMAN_COLLECTION_NAME'| translate}}"  ng-cloak>
+    <form name="collectionForm">
+        <md-toolbar>
+            <div class="md-toolbar-tools">
+                <h2>{{(dialog.duplicate ? 'YANGMAN_COLLECTION_DUPLICATE' : 'YANGMAN_COLLECTION_CHANGE_NAME')| translate}}</h2>
+                <span flex></span>
+            </div>
+        </md-toolbar>
+        <md-dialog-content style="width:300px;">
+            <div class="md-dialog-content" layout="column">
+                <div layout="row">
+                    <md-input-container flex>
+                        <label>{{(dialog.duplicate ? 'YANGMAN_COLLECTION_NEW_NAME' : 'YANGMAN_COLLECTION_NAME') | translate}}</label>
+                        <input name="collectionName"
+                               ng-model="dialog.collectionName"
+                               autocomplete="off"
+                               ng-required="true">
+                        <div ng-messages="collectionForm.collectionName.$error" multiple md-auto-hide="false">
+                            <div ng-message="required">
+                                {{'YANGMAN_COLLECTION_NAME_REQUIRED'| translate}}
+                            </div>
+                        </div>
+                    </md-input-container>
+                </div>
+            </div>
+        </md-dialog-content>
+        <md-dialog-actions layout="row">
+            <span flex></span>
+            <md-button ng-click="dialog.cancel()">
+                {{'YANGMAN_CANCEL'| translate}}
+            </md-button>
+            <md-button ng-click="dialog.save()" ng-disabled="!collectionForm.$valid">
+                {{'YANGMAN_SAVE'| translate}}
+            </md-button>
+        </md-dialog-actions>
+    </form>
+</md-dialog>
diff --git a/modules/yangman-resources/src/main/resources/yangman/views/leftpanel/history-tab.tpl.html b/modules/yangman-resources/src/main/resources/yangman/views/leftpanel/history-tab.tpl.html
new file mode 100644 (file)
index 0000000..f6560d0
--- /dev/null
@@ -0,0 +1,141 @@
+<md-list class="yangmanModule__requests-list h100"
+         ng-cloak
+         ng-init="reqList.init('history')"
+         ng-controller="RequestsListCtrl as reqList">
+
+    <md-content class="searchBox yangmanModule__left-panel__search" layout="row">
+
+        <!-- searching -->
+        <md-input-container layout="row" md-no-float class="modules-list-search" flex>
+            <!-- search icon, form, clear button -->
+            <md-icon class="material-icons">search</md-icon>
+            <input class="ng-pristine ng-valid ng-touched"
+                   type="text"
+                   flex
+                   placeholder="{{'YANGMAN_SEARCH' | translate}}"
+                   ng-model="reqList.search"
+                   aria-invalid="false" />
+            <md-button aria-label="{{'YANGMAN_CLEAR_SEARCH'| translate}}" flex="none"
+                       ng-click="reqList.clearFilter()"
+                       ng-if="reqList.search">
+                <md-icon class="material-icons clickable">
+                    close
+                </md-icon>
+                <md-tooltip md-direction="bottom">{{'YANGMAN_CLEAR_SEARCH'| translate}}</md-tooltip>
+            </md-button>
+            <!-- /search icon, form, clear button -->
+        </md-input-container>
+
+        <!-- save -->
+        <md-button  ng-click="reqList.showDgSaveReq($event)"
+                    ng-disabled="!reqList.mainList.getSelectedItems(reqList.filterReq).length">
+            <md-icon class="material-icons clickable">
+                save
+            </md-icon>
+            <md-tooltip md-direction="bottom">{{'YANGMAN_REQS_SAVE_TO_COL'| translate}}</md-tooltip>
+        </md-button>
+        <!-- /save -->
+
+        <!-- menu for deleting and clearing-->
+        <md-menu layout-align="center start">
+            <md-button ng-disabled="!reqList.mainList.list.length" aria-label="menu"  ng-click="$mdOpenMenu()">
+                <md-icon class="material-icons clickable"> delete</md-icon>
+                <md-tooltip md-direction="bottom">{{'YANGMAN_DELETE_OPTIONS' | translate}}</md-tooltip>
+            </md-button>
+            <md-menu-content>
+                <!-- delete selected -->
+                <md-menu-item>
+                    <md-button aria-label="{{'YANGMAN_REQS_DELETE'| translate}}"
+                               ng-click="reqList.showDgDeleteRequests($event)"
+                               ng-disabled="!reqList.mainList.getSelectedItems(reqList.filterReq).length">
+                        <md-icon class="material-icons clickable"> delete</md-icon>
+                        {{'YANGMAN_REQS_DELETE'| translate}}
+                    </md-button>
+                </md-menu-item>
+                <!-- / delete selected -->
+                <!-- clear history -->
+                <md-menu-item>
+                    <md-button aria-label="{{'YANGMAN_DELETE_HISTORY' | translate}}"
+                               ng-click="reqList.clearHistoryList($event)"
+                               ng-disabled="!reqList.mainList.list.length">
+                        <md-icon class="material-icons clickable"> delete_forever</md-icon>
+                        {{'YANGMAN_DELETE_HISTORY' | translate}}
+                    </md-button>
+                </md-menu-item>
+                <!-- / clear history -->
+            </md-menu-content>
+        </md-menu>
+        <!-- / menu for deleting and clearing -->
+
+        <!-- menu for selecting and deselecting-->
+        <md-menu layout-align="center start">
+            <md-button ng-disabled="!reqList.mainList.list.length" aria-label="menu"  ng-click="$mdOpenMenu()">
+                <md-icon class="material-icons clickable">
+                    playlist_add_check
+                </md-icon>
+                <md-tooltip md-direction="bottom">{{'YANGMAN_SELECT_OPTIONS' | translate}}</md-tooltip>
+            </md-button>
+            <md-menu-content>
+                <!-- select all -->
+                <md-menu-item>
+                    <md-button aria-label="{{'YANGMAN_SELECT_ALL' | translate}}"
+                               ng-click="reqList.selectAllFilteredRequests()">
+                        <md-icon class="material-icons clickable">
+                            done
+                        </md-icon>
+                        {{'YANGMAN_SELECT_ALL' | translate}}
+                    </md-button>
+                </md-menu-item>
+                <!-- /select all -->
+                <!-- deselect all -->
+                <md-menu-item>
+                    <md-button aria-label="{{'YANGMAN_DESELECT_ALL' | translate}}"
+                               ng-click="reqList.deselectAllFilteredRequests()" ng-disabled="reqList.mainList.getSelectedItems(reqList.filterReq).length === 0">
+                        <md-icon class="material-icons clickable">
+                            close
+                        </md-icon>
+                        {{'YANGMAN_DESELECT_ALL' | translate}}
+                    </md-button>
+                </md-menu-item>
+                <!-- / deselect all -->
+            </md-menu-content>
+        </md-menu>
+        <!-- / menu for selecting and deselecting -->
+
+    </md-content>
+
+    <md-divider></md-divider>
+
+    <!-- list of items grouped by date -->
+    <md-content class="scrollableY">
+        <md-list-item ng-repeat="group in reqList.mainList.dateGroups | orderBy: 'name': true"
+                      class="yangmanModule__requests-list__group"
+                      ng-if="(group.requests | filter:reqList.filterReq).length">
+
+            <div layout="column" flex>
+
+                <!-- date group header -->
+                <md-subheader class="md-no-sticky">
+                    {{group.longName}}
+                </md-subheader>
+                <!-- /date group header -->
+
+                <!-- list of requests in current group -->
+                <md-list>
+                    <div ng-repeat="request in group.requests | filter: reqList.filterReq  | orderBy: '-timestamp' track by $index"
+                         layout="row"
+                         class="yangmanModule__requests-list__item-container"
+                         ng-include src="globalViewPath + 'leftpanel/request-item.tpl.html'">
+                    </div>
+                </md-list>
+                <!-- /list of requests in current group -->
+
+            </div>
+
+            <md-divider></md-divider>
+
+        </md-list-item>
+    </md-content>
+    <!-- /list of items grouped by date -->
+
+</md-list>
diff --git a/modules/yangman-resources/src/main/resources/yangman/views/leftpanel/module-detail.tpl.html b/modules/yangman-resources/src/main/resources/yangman/views/leftpanel/module-detail.tpl.html
new file mode 100644 (file)
index 0000000..62bce5d
--- /dev/null
@@ -0,0 +1,25 @@
+<md-content ng-controller="ModuleDetailCtrl as moduleDetail">
+    <!-- Module title -->
+    <h4 class="text-center"><small>module</small> {{selectedModule.label}}</h4>
+    <!-- DATA STORE || RPC TABS -->
+    <md-tabs md-no-pagination md-dynamic-height
+             md-stretch-tabs="always"
+             md-selected="moduleDetail.selectedDataStoreIndex"
+             class="tabs inline-tabs">
+        <md-tab ng-repeat="item in selectedModule.children">
+            <md-tab-label>
+                <div layout="row">
+                    <span flex="grow" ng-click="moduleDetail.setDataDetailStore(item)">{{item.label}}</span>
+                </div>
+            </md-tab-label>
+
+            <md-tab-body>
+                <div class="scrollableY scrollableX">
+                    <abn-api-tree tree-data="moduleDetail.treeApis"
+                                  tree-rows="moduleDetail.treeRows"
+                                  on-select="moduleDetail.setApiNode(branch.indexApi, branch.indexSubApi)"></abn-api-tree>
+                </div>
+            </md-tab-body>
+        </md-tab>
+    </md-tabs>
+</md-content>
diff --git a/modules/yangman-resources/src/main/resources/yangman/views/leftpanel/modules-tab.tpl.html b/modules/yangman-resources/src/main/resources/yangman/views/leftpanel/modules-tab.tpl.html
new file mode 100644 (file)
index 0000000..399f233
--- /dev/null
@@ -0,0 +1,76 @@
+<section ng-cloak ng-controller="ModulesListCtrl as modulesList" class="h100">
+    <!-- searching -->
+    <section class="yangmanModule__left-panel__search">
+        <md-input-container layout="row" md-no-float class="modules-list-search">
+            <md-icon class="material-icons">search</md-icon>
+            <input class="ng-pristine ng-valid ng-touched"
+                   type="text"
+                   flex
+                   placeholder="{{'YANGMAN_SEARCH' | translate}}"
+                   ng-model="modulesList.search"
+                   aria-invalid="false" />
+
+            <!-- search clear button -->
+            <md-button aria-label="{{'YANGMAN_CLEAR_SEARCH'| translate}}" flex="none"
+                       ng-click="modulesList.clearFilter()"
+                       ng-if="modulesList.search">
+                <md-icon class="material-icons clickable">
+                    close
+                </md-icon>
+                <md-tooltip md-direction="bottom">{{'YANGMAN_CLEAR_SEARCH'| translate}}</md-tooltip>
+            </md-button>
+        </md-input-container>
+
+    </section>
+
+    <!-- divider -->
+    <md-divider ng-hide="modulesList.showLoadingBox"></md-divider>
+
+    <!-- modules list -->
+    <md-list ng-cloak class="yangmanModule__modules-list scrollableY">
+
+        <!-- Loading bar -->
+        <md-progress-linear md-mode="indeterminate" ng-show="modulesList.showLoadingBox"></md-progress-linear>
+
+        <!-- Mount point title -->
+        <section ng-show="modulesList.moduleListTitle.length">
+            <h4>{{ modulesList.moduleListTitle }}</h4>
+            <!-- Line -->
+            <md-divider></md-divider>
+        </section>
+
+        <!-- Modules list -->
+        <md-list-item ng-repeat="module in modulesList.treeApis | filter: modulesList.customSearch | orderBy: 'label'"
+                      class="yangmanModule__modules-list__item"
+                      ng-class="{'expanded' : module.expanded, 'selected' : modulesList.checkSelectedModule(module)}"
+                      ng-hide="modulesList.showLoadingBox"
+                      ng-click="modulesList.setModule(module, $event)">
+            <!-- Item content -->
+            <div layout="column" flex>
+                <!-- Module title -->
+                <div layout="row" layout-align="center center"  class="pointer title">
+                    <md-icon md-font-set="material-icons" class="top-icon top-element">
+                        {{module.expanded ? 'keyboard_arrow_down':'keyboard_arrow_right'}}
+                    </md-icon>
+                    <p flex class="top-element" md-highlight-text="modulesList.search" md-highlight-flags="i"> {{module.label}} </p>
+                </div>
+
+                <!-- Datastore && rpc -->
+                <md-list flex class="yangmanModule__datastore-list" ng-show="module.expanded">
+                    <md-list-item ng-repeat="item in module.children">
+                        <div flex
+                             layout="row"
+                             layout-align="center center"
+                             class="pointer"
+                             ng-click="modulesList.setDataStore(item, module)">
+                            <md-icon md-font-set="material-icons">keyboard_arrow_right</md-icon>
+                            <p flex> {{item.label}} </p>
+                        </div>
+                    </md-list-item>
+                </md-list>
+            </div>
+            <!-- Line -->
+            <md-divider></md-divider>
+        </md-list-item>
+    </md-list>
+</section>
diff --git a/modules/yangman-resources/src/main/resources/yangman/views/leftpanel/request-item.tpl.html b/modules/yangman-resources/src/main/resources/yangman/views/leftpanel/request-item.tpl.html
new file mode 100644 (file)
index 0000000..7905423
--- /dev/null
@@ -0,0 +1,67 @@
+<!-- request row -->
+<md-list-item class="yangmanModule__requests-list__group__item"
+              ng-class="{selected: request.selected}"
+              layout="row"
+              flex="100"
+              ng-click="reqList.selectRequest($event, request);">
+
+    <div flex="15" class="yangmanModule__requests-list__group__item__method" layout-align="center center">
+        <p class="{{request.status === 'success' || !request.status ? request.method : 'error'}}"> {{request.method === vm.constants.OPERATION_DELETE ? 'DEL' : request.method }} </p>
+        <md-tooltip md-direction="bottom" ng-show="request.status">{{request.status | uppercase }}</md-tooltip>
+    </div>
+
+    <div flex class="yangmanModule__requests-list__group__item__path" layout="column">
+        <p md-highlight-text="reqList.search" md-highlight-flags="i">
+            {{ request.path }}
+        </p>
+    </div>
+    <div flex="10"></div>
+</md-list-item>
+<!-- /request row -->
+
+<!-- request submenu -->
+<md-menu class="yangmanModule__requests-list__group__itemMenu"
+         md-offset="35 15"
+         layout-align="center start"
+         ng-class="{selected: request.selected}">
+
+    <md-button aria-label="menu" class="md-primary" ng-click="reqList.selectOnlyThisRequest(request); $mdOpenMenu()">
+        <i class="material-icons">menu</i>
+    </md-button>
+
+    <md-menu-content class="reqMenu">
+        <md-menu-item>
+            <md-button aria-label="{{'YANGMAN_REQ_RUN'| translate}}" class="" ng-click="reqList.executeRequest(request)">
+                <i class="material-icons">play_arrow</i>
+                {{'YANGMAN_REQ_RUN'| translate}}
+            </md-button>
+        </md-menu-item>
+        <md-menu-item>
+            <md-button aria-label="{{'YANGMAN_REQ_SHOW_FORM'| translate}}" ng-click="reqList.showForm(request)">
+                <i class="material-icons">exit_to_app</i>
+                {{'YANGMAN_REQ_SHOW_FORM'| translate}}
+            </md-button>
+        </md-menu-item>
+        <md-menu-item>
+            <md-button aria-label="{{'YANGMAN_REQ_SHOW_SENT_DATA'| translate}}"
+                       ng-click="reqList.showData(request)">
+                <i class="material-icons">call_made</i>
+                {{'YANGMAN_REQ_SHOW_JSON_DATA'| translate}}
+            </md-button>
+        </md-menu-item>
+        <md-menu-item ng-if="request.collection.length">
+            <md-button aria-label="{{'YANGMAN_REQ_DUPLICATE'| translate}}"
+                       ng-click="reqList.showDgSaveReq($event, request, true)">
+                <i class="material-icons">control_point_duplicate</i>
+                {{'YANGMAN_REQ_DUPLICATE'| translate}}
+            </md-button>
+        </md-menu-item>
+        <md-menu-item>
+            <md-button aria-label="{{'YANGMAN_REQ_DELETE'| translate}}" ng-click="reqList.showDgDeleteRequests($event, request)">
+                <i class="material-icons">delete</i>
+                {{'YANGMAN_REQ_DELETE'| translate}}
+            </md-button>
+        </md-menu-item>
+    </md-menu-content>
+</md-menu>
+<!-- /request submenu -->
diff --git a/modules/yangman-resources/src/main/resources/yangman/views/leftpanel/save-req-dialog.tpl.html b/modules/yangman-resources/src/main/resources/yangman/views/leftpanel/save-req-dialog.tpl.html
new file mode 100644 (file)
index 0000000..2983e63
--- /dev/null
@@ -0,0 +1,54 @@
+<md-dialog aria-label="Save to collection"  ng-cloak>
+    <form name="dialog.saveReqForm">
+        <md-toolbar>
+            <div class="md-toolbar-tools">
+                <h2>{{( dialog.duplicate ? 'YANGMAN_REQS_DUPLICATE' : 'YANGMAN_REQS_SAVE_TO_COL')| translate}}</h2>
+                <span flex></span>
+            </div>
+        </md-toolbar>
+        <md-dialog-content style="width: 400px;">
+            <div class="md-dialog-content" layout="column">
+                <md-input-container>
+                    <md-autocomplete
+                            md-selected-item="dialog.selectedItem"
+                            md-search-text="dialog.collectionName"
+                            md-items="item in dialog.getColAutocomplete()"
+                            md-floating-label="{{'YANGMAN_CREATING_COLLECTION'|translate}}"
+                            md-item-text="item"
+                            md-min-length="0"
+                            ng-required="true">
+                        <md-item-template>
+                            <span md-highlight-text="dialog.collectionName" md-highlight-flags="^i">{{item}}</span>
+                        </md-item-template>
+                        <md-not-found>
+                        <span ng-if="dialog.collectionName.length">
+                            {{'YANGMAN_COLLECTION_NEW_COL_'| translate}} "{{dialog.collectionName}}" {{'YANGMAN_COLLECTION_WILL_BE_CREATED'| translate}}.
+                        </span>
+                        <span ng-if="dialog.collectionName.length === 0">
+                            {{'YANGMAN_NO_COLLECTIONS'| translate}}
+                        </span>
+                        </md-not-found>
+                    </md-autocomplete>
+                    <input name="collectionName"
+                           ng-model="dialog.collectionName"
+                           ng-required="true" style="display: none;">
+                    <div ng-messages="dialog.saveReqForm.collectionName.$error" multiple md-auto-hide="false">
+                        <div ng-message="required">
+                            {{'YANGMAN_COLLECTION_NAME_REQUIRED'| translate}}
+                        </div>
+                    </div>
+                </md-input-container>
+
+            </div>
+        </md-dialog-content>
+        <md-dialog-actions layout="row">
+            <span flex></span>
+            <md-button ng-click="dialog.cancel()">
+                {{'YANGMAN_CANCEL'| translate}}
+            </md-button>
+            <md-button ng-click="dialog.save()" ng-disabled="!dialog.saveReqForm.$valid">
+                {{'YANGMAN_SAVE'| translate}}
+            </md-button>
+        </md-dialog-actions>
+    </form>
+</md-dialog>
diff --git a/modules/yangman-resources/src/main/resources/yangman/views/popup/parameters-admin.tpl.html b/modules/yangman-resources/src/main/resources/yangman/views/popup/parameters-admin.tpl.html
new file mode 100644 (file)
index 0000000..9a1d17d
--- /dev/null
@@ -0,0 +1,170 @@
+<md-dialog aria-label="{{'YANGMAN_PARAMETERS_ADMINISTRATION'| translate}}"  ng-cloak>
+    <form name="paramsAdmin.paramsForm">
+        <md-toolbar>
+            <div class="md-toolbar-tools">
+                <h2>{{'YANGMAN_PARAMETERS_ADMINISTRATION'| translate}}</h2>
+                <span flex></span>
+                <md-button aria-label="{{'YANGMAN_CLOSE'| translate}}"
+                           ng-click="paramsAdmin.close()">
+                    <md-icon class="material-icons clickable" >
+                        close
+                    </md-icon>
+                    <md-tooltip md-direction="bottom">{{'YANGMAN_CLOSE'| translate}}</md-tooltip>
+                </md-button>
+            </div>
+        </md-toolbar>
+        <md-dialog-content class="paramsAdminDialog" layout="column">
+            <div class="md-dialog-content" layout="column">
+                <!-- top part for search and sort bar -->
+                <div class="paramsAdminDialog__searchBox" layout="row">
+
+                    <!-- search icon, form, clear button -->
+                    <md-icon class="material-icons">search</md-icon>
+                    <input class=""
+                           type="text"
+                           flex
+                           ng-change="paramsAdmin.filterChange()"
+                           placeholder="{{'YANGMAN_SEARCH' | translate}}"
+                           ng-model="paramsAdmin.search"
+                           aria-invalid="false" />
+                    <md-button aria-label="{{'YANGMAN_CLEAR_SEARCH'| translate}}"
+                               ng-click="paramsAdmin.clearFilter()"
+                               ng-if="paramsAdmin.search">
+                        <md-icon class="material-icons clickable" >
+                            close
+                        </md-icon>
+                        <md-tooltip md-direction="bottom">{{'YANGMAN_CLEAR_SEARCH'| translate}}</md-tooltip>
+                    </md-button>
+                    <!-- /search icon, form, clear button -->
+
+                    <!-- sorting menu -->
+                    <md-menu md-offset="35 15" layout-align="center start">
+                        <md-button aria-label="{{'YANGMAN_SORT'| translate}}" class="" ng-click="$mdOpenMenu()">
+                            <i class="material-icons">sort</i>
+                            <md-tooltip md-direction="bottom">
+                                {{'YANGMAN_SORTING' | translate}}
+                            </md-tooltip>
+                        </md-button>
+                        <md-menu-content>
+                            <!-- sort by name -->
+                            <md-menu-item>
+                                <md-button aria-label="{{'YANGMAN_PARAMS_KEY'| translate}}"
+                                           ng-click="paramsAdmin.sortBy('_name', '_value')">
+                                    {{'YANGMAN_SORT_BY'| translate}}
+                                    {{'YANGMAN_PARAMS_KEY'| translate}}
+                                    {{paramsAdmin.sortAsc ? 'YANGMAN_SORT_DESC' : 'YANGMAN_SORT_ASC' | translate}}
+                                </md-button>
+                            </md-menu-item>
+                            <!-- /sort by name -->
+
+                            <!-- sort by value -->
+                            <md-menu-item>
+                                <md-button aria-label="{{'YANGMAN_PARAMS_VALUE'| translate}}"
+                                           ng-click="paramsAdmin.sortBy('_value', '_name')">
+                                    {{'YANGMAN_SORT_BY'| translate}}
+                                    {{'YANGMAN_PARAMS_VALUE'| translate}}
+                                    {{paramsAdmin.sortAsc ? 'YANGMAN_SORT_DESC' : 'YANGMAN_SORT_ASC' | translate}}
+                                </md-button>
+                            </md-menu-item>
+                            <!-- /sort by value -->
+
+                        </md-menu-content>
+                    </md-menu>
+                    <!-- /sorting menu -->
+
+                    <!-- menu for import and export parameters -->
+                    <input type="file" accept=".json" id="importParameters" on-read-file="paramsAdmin.importParameters($fileContent)">
+                    <md-menu md-offset="35 15" layout-align="center start">
+                        <md-button aria-label="{{ 'YANGMAN_PARAMS_IMPORT_EXPORT' | translate }}" ng-click="$mdOpenMenu()">
+                            <i class="material-icons">import_export</i>
+                            <md-tooltip md-direction="bottom">
+                                {{ 'YANGMAN_PARAMS_IMPORT_EXPORT' | translate }}
+                            </md-tooltip>
+                        </md-button>
+                        <md-menu-content>
+                            <md-menu-item>
+                                <md-button>
+                                    <label for="importParameters">
+                                        {{'YANGMAN_IMPORT_PARAMS'| translate}}
+                                    </label>
+                                </md-button>
+                            </md-menu-item>
+                            <md-menu-item>
+                                <md-button aria-label="{{'YANGMAN_EXPORT_PARAMETERS' | translate}}" ng-click="paramsAdmin.exportParameters()">
+                                    {{'YANGMAN_EXPORT_PARAMETERS' | translate}}
+                                </md-button>
+                            </md-menu-item>
+                        </md-menu-content>
+                    </md-menu>
+                    <!-- /menu for import and export parameters -->
+
+                </div>
+
+                <md-divider></md-divider>
+                <!-- /top part for search and sort bar -->
+
+                <!-- parameters list -->
+                <md-content class="paramsAdminDialog__paramsList scrollableY" layout="column">
+
+                    <div layout="row"
+                         ng-repeat="param in paramsAdmin.parametersList.list |
+                                        filter: paramsAdmin.filterParam |
+                                        orderBy: paramsAdmin.sortFunc : !paramsAdmin.sortAsc
+                                        track by $index">
+                        <!-- name input -->
+                        <md-input-container>
+                            <label>{{'YANGMAN_PARAM_KEY' | translate}}</label>
+                            <input name="name_{{$index}}"
+                                   ng-model="param.name"
+                                   ng-required="param.value"
+                                   ng-change="paramsAdmin.validateNamesUnique()"
+                                   ng-focus="$last && paramsAdmin.createEmptyParam()"
+                                   autocomplete="off">
+                            <div ng-messages="paramsAdmin.paramsForm['name_'+$index].$error" multiple md-auto-hide="false">
+                                <div ng-message="required">
+                                    {{'YANGMAN_PARAM_KEY_REQUIRED'| translate}}
+                                </div>
+                                <div ng-message="unique">
+                                    {{'YANGMAN_PARAM_EXISTING_KEY'| translate}}
+                                </div>
+                            </div>
+                        </md-input-container>
+                        <!-- / name input -->
+
+                        <!-- value input -->
+                        <md-input-container flex>
+                            <label>{{'YANGMAN_PARAM_VALUE' | translate}}</label>
+                            <input ng-model="param.value" ng-focus="$last && paramsAdmin.createEmptyParam()">
+                        </md-input-container>
+                        <!-- /value input -->
+
+                        <!-- remove param button -->
+                        <md-button aria-label="{{'YANGMAN_REMOVE_PARAM' | translate}}"
+                                   class=""
+                                   ng-if="!$last"
+                                   ng-click="paramsAdmin.removeParam(param)">
+                            <md-tooltip md-direction="bottom">
+                                {{'YANGMAN_REMOVE_PARAM' | translate}}
+                            </md-tooltip>
+                            <i class="material-icons">close</i>
+                        </md-button>
+                        <!-- /remove param button -->
+
+
+                    </div>
+                </md-content>
+                <!-- /parameters list -->
+
+            </div>
+        </md-dialog-content>
+        <md-dialog-actions layout="row">
+            <span flex></span>
+            <md-button ng-click="paramsAdmin.close()">
+                {{'YANGMAN_CLOSE'| translate}}
+            </md-button>
+            <md-button ng-click="paramsAdmin.save()" ng-disabled="!paramsAdmin.paramsForm.$valid">
+                {{'YANGMAN_SAVE'| translate}}
+            </md-button>
+        </md-dialog-actions>
+    </form>
+</md-dialog>
diff --git a/modules/yangman-resources/src/main/resources/yangman/views/rightpanel/detail.tpl.html b/modules/yangman-resources/src/main/resources/yangman/views/rightpanel/detail.tpl.html
new file mode 100644 (file)
index 0000000..519cd5e
--- /dev/null
@@ -0,0 +1,88 @@
+<!-- Header -->
+<section md-whiteframe="1"
+         class="yangmanModule__right-panel__header"
+         style="margin-bottom: 0px!important;"
+         ng-include src="globalViewPath + 'rightpanel/request-header.tpl.html'">
+</section>
+<!-- /Header -->
+
+<!--<section class="yangmanModule__right-panel__request-progress">-->
+    <!--<div class="yangmanModule__right-panel__request-progress__loading-container">-->
+        <!--<md-progress-linear md-mode="query"></md-progress-linear>-->
+        <!--<div class="bottom-block">-->
+            <!--<span>{{ 'YANGMAN_EXECUTING_REQUEST' | translate }}...</span>-->
+        <!--</div>-->
+    <!--</div>-->
+<!--</section>-->
+
+<!-- Form section -->
+<section class="yangmanModule__right-panel__form bottom-content"
+         ng-show="rightPanelSection === main.constants.DISPLAY_TYPE_FORM"
+         ng-if="node"
+         ng-controller="YangFormCtrl as yangForm">
+    <div ng-show="yangForm.errorMsg"><p class="error">{{ yangForm.errorMsg }}</p></div>
+    <div ng-include src="yangForm.viewPath + '/' + selectedDatastore.label + '/' + node.type+'.tpl.html'"></div>
+</section>
+<!-- /Form section -->
+
+<!-- JSON section -->
+<section class="yangmanModule__right-panel__req-data bottom-content"
+         ng-cloak
+         ng-show="rightPanelSection === main.constants.DISPLAY_TYPE_REQ_DATA">
+
+    <!-- Sent data -->
+    <div ng-controller="RequestDataCtrl as requestData"
+         layout="column"
+         ng-show="main.jsonView.sent"
+         ng-init="requestData.init('SENT')"
+         ng-class="{'half-size': main.jsonView.received && main.jsonView.sent}"
+         class="yangmanModule__right-panel__req-data__cm-SENT ym-resizable-s">
+
+        <section class="yangmanModule__right-panel__req-data__header" layout="row">
+            <h5 flex>{{'YANGMAN_SENT_DATA' | translate}}</h5>
+            <md-button ng-click="requestData.enlargeCMFont()">
+                <i class="material-icons bigger">text_format</i>
+                <i class="material-icons additional">arrow_drop_up</i>
+                <md-tooltip>
+                    {{ 'YANGMAN_CM_ENLARGE_FONT_SIZE' | translate }}
+                </md-tooltip>
+            </md-button>
+            <md-button ng-click="requestData.reduceCMFont()">
+                <i class="material-icons smaller">text_format</i>
+                <i class="material-icons additional">arrow_drop_down</i>
+                <md-tooltip md-direction="bottom right">
+                    {{ 'YANGMAN_CM_REDUCE_FONT_SIZE' | translate }}
+                </md-tooltip>
+            </md-button>
+        </section>
+        <div md-whiteframe="2" ng-include src="globalViewPath + 'rightpanel/request-data.tpl.html'"></div>
+    </div>
+
+    <!-- Received data -->
+    <div ng-controller="RequestDataCtrl as requestData"
+         ng-show="main.jsonView.received"
+         ng-init="requestData.init(main.constants.REQUEST_DATA_TYPE_RECEIVED)"
+         ng-class="{'half-size': main.jsonView.received && main.jsonView.sent}"
+         class="yangmanModule__right-panel__req-data__cm-RECEIVED ym-resizable-s">
+
+        <section class="yangmanModule__right-panel__req-data__header" layout="row">
+            <h5 flex>{{'YANGMAN_RECEIVED_DATA' | translate}}</h5>
+            <md-button ng-click="requestData.enlargeCMFont()">
+                <i class="material-icons bigger">text_format</i>
+                <i class="material-icons additional">arrow_drop_up</i>
+                <md-tooltip>
+                    {{ 'YANGMAN_CM_ENLARGE_FONT_SIZE' | translate }}
+                </md-tooltip>
+            </md-button>
+            <md-button ng-click="requestData.reduceCMFont()">
+                <i class="material-icons smaller">text_format</i>
+                <i class="material-icons additional">arrow_drop_down</i>
+                <md-tooltip md-direction="bottom right">
+                    {{ 'YANGMAN_CM_REDUCE_FONT_SIZE' | translate }}
+                </md-tooltip>
+            </md-button>
+        </section>
+        <div md-whiteframe="2" ng-include src="globalViewPath + 'rightpanel/request-data.tpl.html'"></div>
+    </div>
+</section>
+<!-- /JSON section -->
diff --git a/modules/yangman-resources/src/main/resources/yangman/views/rightpanel/form/augmentations.tpl.html b/modules/yangman-resources/src/main/resources/yangman/views/rightpanel/form/augmentations.tpl.html
new file mode 100644 (file)
index 0000000..f25bdb8
--- /dev/null
@@ -0,0 +1,8 @@
+<md-list flex>
+    <md-list-item ng-repeat="augmentation in node.augmentionGroups">
+        <md-switch ng-model="augmentations.getAugmentation(node, augmentation).expanded" aria-label="{{augmentation}}">
+            {{augmentation}}
+        </md-switch>
+    </md-list-item>
+
+</md-list>
\ No newline at end of file
diff --git a/modules/yangman-resources/src/main/resources/yangman/views/rightpanel/form/config/case.tpl.html b/modules/yangman-resources/src/main/resources/yangman/views/rightpanel/form/config/case.tpl.html
new file mode 100644 (file)
index 0000000..3c4e3a0
--- /dev/null
@@ -0,0 +1,6 @@
+<div ng-controller="YMCaseCtrl as yangCase" ng-hide="yangCase.empty">
+    <!-- case's children -->
+    <div ng-repeat="node in case.getChildren(null,null,constants.NODE_UI_DISPLAY) | ymOnlyConfigElem"
+         ng-include="yangForm.viewPath + '/config/' + node.type + '.tpl.html'"
+         ng-hide="node.augmentationId && !augmentations.getAugmentation(node.parent, node.augmentationId).expanded"></div>
+</div>
diff --git a/modules/yangman-resources/src/main/resources/yangman/views/rightpanel/form/config/choice.tpl.html b/modules/yangman-resources/src/main/resources/yangman/views/rightpanel/form/config/choice.tpl.html
new file mode 100644 (file)
index 0000000..d316e2f
--- /dev/null
@@ -0,0 +1,39 @@
+<div ng-controller="YMChoiceCtrl as yangChoice"
+     class="yangmanModule__right-panel__form__element-container"
+     ng-class="{'expanded' : node.expanded}">
+
+    <!-- choice title -->
+    <div layout="row"
+         layout-align="start center"
+         class="pointer container-label">
+
+        <!-- Expand Icon -->
+        <md-icon md-font-set="material-icons" class="top-icon top-element" ng-click="yangChoice.toggleExpanded()">
+            <md-tooltip md-direction="left">{{ 'YANGMAN_SHOW_HIDE_CON' | translate }}</md-tooltip>
+            {{node.expanded ? 'keyboard_arrow_down':'keyboard_arrow_right'}}
+        </md-icon>
+
+        <!-- Choice label -->
+        <p class="top-element" ym-info-box node="node" ng-click="yangChoice.toggleExpanded()"> {{yangForm.getNodeName(node.localeLabel, node.label)}} </p>
+
+        <!-- Action menu -->
+        <yang-form-menu is-action-menu="yangChoice.isActionMenu()"
+                        augmentations="augmentations"
+                        node="node"></yang-form-menu>
+
+        <!-- Choice select -->
+        <md-input-container>
+            <md-select ng-model="node.choice" aria-label="Choice select">
+                <md-option ng-repeat="node in node.getChildren(null, null, constants.NODE_UI_DISPLAY) | filter:caseShowing" ng-value="node">
+                    {{node.label}}
+                </md-option>
+            </md-select>
+        </md-input-container>
+    </div>
+
+    <!-- choice's children -->
+    <div ng-repeat="case in node.getChildren(null,null,constants.NODE_UI_DISPLAY) | ymOnlyConfigElem"
+         ng-include="yangForm.viewPath + '/config/' + case.type +'.tpl.html'"
+         ng-show="node.choice.id === case.id && node.expanded"
+         ng-if="!(case.augmentationId && !augmentations.getAugmentation(case.parent, case.augmentationId).expanded)"></div>
+</div>
diff --git a/modules/yangman-resources/src/main/resources/yangman/views/rightpanel/form/config/container.tpl.html b/modules/yangman-resources/src/main/resources/yangman/views/rightpanel/form/config/container.tpl.html
new file mode 100644 (file)
index 0000000..40840cc
--- /dev/null
@@ -0,0 +1,40 @@
+<div ng-controller="YMContainerCtrl as yangContainer"
+     class="yangmanModule__right-panel__form__element-container"
+     ng-class="{'expanded' : node.expanded}">
+
+    <!-- container title -->
+    <div layout="row"
+         layout-align="start center"
+         class="pointer container-label">
+
+        <!-- Expand Icon -->
+        <md-icon md-font-set="material-icons"
+                 class="top-icon top-element pointer"
+                 ng-click="yangContainer.toggleExpanded()">
+
+            <md-tooltip md-direction="left">{{ 'YANGMAN_SHOW_HIDE_CON' | translate }}</md-tooltip>
+            {{node.expanded ? 'keyboard_arrow_down':'keyboard_arrow_right'}}
+        </md-icon>
+
+        <!-- Container label -->
+        <p class="top-element pointer"
+           ng-click="yangContainer.toggleExpanded()" ym-info-box node="node">
+
+            {{yangForm.getNodeName(node.localeLabel, node.label)}}
+        </p>
+
+        <!-- Action menu -->
+        <yang-form-menu is-action-menu="yangContainer.isActionMenu()"
+                        augmentations="augmentations"
+                        node="node"></yang-form-menu>
+
+    </div>
+
+    <!-- container's children -->
+    <div ng-if="node.expanded">
+        <div ng-repeat="node in node.getChildren(null,null,constants.NODE_UI_DISPLAY) | ymOnlyConfigElem"
+             ng-include="yangForm.viewPath + '/config/' + node.type+'.tpl.html'"
+             ng-hide="node.augmentationId && !augmentations.getAugmentation(node.parent, node.augmentationId).expanded">
+        </div>
+    </div>
+</div>
diff --git a/modules/yangman-resources/src/main/resources/yangman/views/rightpanel/form/config/input.tpl.html b/modules/yangman-resources/src/main/resources/yangman/views/rightpanel/form/config/input.tpl.html
new file mode 100644 (file)
index 0000000..7cde3b1
--- /dev/null
@@ -0,0 +1,34 @@
+<div ng-controller="YMInputCtrl as yangInput"
+     class="yangmanModule__right-panel__form__element-container"
+     ng-class="{'expanded' : node.expanded}">
+
+    <!-- container title -->
+    <div layout="row"
+         layout-align="start center"
+         class="pointer container-label"
+         ng-click="yangInput.toggleExpanded()">
+
+        <!-- Expand Icon -->
+        <md-icon md-font-set="material-icons" class="top-icon top-element">
+            <md-tooltip md-direction="left">{{ 'YANGMAN_SHOW_HIDE_CON' | translate }}</md-tooltip>
+            {{node.expanded ? 'keyboard_arrow_down':'keyboard_arrow_right'}}
+        </md-icon>
+
+        <!-- Container label -->
+        <p class="top-element" ym-info-box node="node"> {{yangForm.getNodeName(node.localeLabel, node.label)}} </p>
+
+        <!-- Action menu -->
+        <yang-form-menu is-action-menu="yangInput.isActionMenu()"
+                        augmentations="augmentations"
+                        node="node"></yang-form-menu>
+
+    </div>
+
+    <!-- output's children -->
+    <div ng-if="node.expanded">
+        <div ng-repeat="node in node.getChildren(null,null,constants.NODE_UI_DISPLAY) | ymOnlyConfigElem"
+             ng-include="yangForm.viewPath + '/config/' + node.type+'.tpl.html'"
+             ng-hide="node.augmentationId && !augmentations.getAugmentation(node.parent, node.augmentationId).expanded">
+        </div>
+    </div>
+</div>
diff --git a/modules/yangman-resources/src/main/resources/yangman/views/rightpanel/form/config/leaf-list.tpl.html b/modules/yangman-resources/src/main/resources/yangman/views/rightpanel/form/config/leaf-list.tpl.html
new file mode 100644 (file)
index 0000000..49d5d8e
--- /dev/null
@@ -0,0 +1,42 @@
+<div ng-controller="YMLeafListCtrl as yangLeafList"
+     class="yangmanModule__right-panel__form__element-container"
+     ng-class="{'expanded' : node.expanded}">
+
+    <!-- container title -->
+    <div layout="row"
+         layout-align="start center"
+         class="pointer container-label">
+
+        <!-- Expand Icon -->
+        <md-icon md-font-set="material-icons" class="top-icon top-element" ng-click="yangLeafList.toggleExpanded()">
+            <md-tooltip md-direction="left">{{ 'YANGMAN_SHOW_HIDE_CON' | translate }}</md-tooltip>
+            {{node.expanded ? 'keyboard_arrow_down':'keyboard_arrow_right'}}
+        </md-icon>
+
+        <!-- Container label -->
+        <p class="top-element" ng-click="yangLeafList.toggleExpanded()" ym-info-box node="node">
+            {{yangForm.getNodeName(node.localeLabel, node.label)}}
+        </p>
+
+        <!-- Action menu -->
+        <yang-form-menu is-action-menu="yangLeafList.isActionMenu()"
+                        augmentations="augmentations"
+                        add-list-item-func="yangLeafList.addListElem()"
+                        add-list-item="true"
+                        node="node"></yang-form-menu>
+    </div>
+
+    <div ng-repeat="elem in node.value" ng-show="node.expanded">
+        <!-- Leaf list values -->
+        <md-input-container md-no-float  class="input-icon-container">
+            <!-- input -->
+            <input  ng-change="yangLeafList.changed()" ng-model="elem.value" aria-label="{{elem.value}}">
+
+            <!-- remove Icon -->
+            <md-icon md-font-set="material-icons" class="top-icon top-element pointer" ng-click="yangLeafList.removeListElem(elem)">
+                <md-tooltip md-direction="right">{{ 'REMOVE_ELEM' | translate }}</md-tooltip>
+                remove_circle_outline
+            </md-icon>
+        </md-input-container>
+    </div>
+</div>
diff --git a/modules/yangman-resources/src/main/resources/yangman/views/rightpanel/form/config/leaf.tpl.html b/modules/yangman-resources/src/main/resources/yangman/views/rightpanel/form/config/leaf.tpl.html
new file mode 100644 (file)
index 0000000..78f410e
--- /dev/null
@@ -0,0 +1,23 @@
+<div ng-controller="YMLeafCtrl as yangLeaf"
+     layout="row"
+     layout-align="start {{yangLeaf.getLeafCentering()}}"
+     class="yangmanModule__right-panel__form__leaf-container {{yangLeaf.getLeafType()}}">
+
+    <!-- Container label -->
+    <p class="top-element" ym-info-box node="node"> {{yangForm.getNodeName(node.localeLabel, node.label)}} </p>
+
+    <!-- Action menu -->
+    <yang-form-menu is-action-menu="yangLeaf.isActionMenu()"
+                    augmentations="augmentations"
+                    node="node"></yang-form-menu>
+
+    <!-- Empty placeholder for better look -->
+    <div class="menu-placeholder" ng-if="!yangLeaf.isActionMenu() && !yangLeaf.isNodeInfo()"></div>
+
+    <div ng-controller="YMTypeCtrl as yangType"
+         ng-repeat="type in node.getChildren('type')"
+         ng-include="yangForm.viewPath + '/config/types/' + yangLeaf.getLeafType() + '.tpl.html'"
+         {{yangLeaf.getLeafType() === 'union' ? 'flex="grow"' : ''}}
+         layout="row">
+    </div>
+</div>
diff --git a/modules/yangman-resources/src/main/resources/yangman/views/rightpanel/form/config/list-filtered-data-top.tpl.html b/modules/yangman-resources/src/main/resources/yangman/views/rightpanel/form/config/list-filtered-data-top.tpl.html
new file mode 100644 (file)
index 0000000..7167146
--- /dev/null
@@ -0,0 +1,33 @@
+<!-- previous item button -->
+<button ng-click="shiftDisplayPrev()"
+        ng-show="showPrevButton()"
+        tooltip="{{ 'YANGMAN_LIST_PREV_ITEM' | translate }}"
+        class="yangButton iconPrev"></button>
+
+<!-- item list -->
+<div class="listButtonWrapper"
+     ng-repeat="offset in displayOffsets"
+     ng-if="currentDisplayIndex + offset > -1 && node.filteredListData.length > currentDisplayIndex + offset">
+
+    <button class="btn btn-like-tab {{ (currentDisplayIndex + offset === node.actElemIndex ? 'btn-selected':'') }}"
+             ng-click="node.changeActElementData(currentDisplayIndex + offset,false)"
+             tooltip="{{getListName(offset, false).tooltip}}">
+        {{yangForm.getNodeName(node.localeLabel, node.label)}}&nbsp;{{ getListName(offset, true).name }}
+    </button>
+
+    <!-- delete button -->
+    <button class="yangButton iconClose"
+            tooltip="{{ 'YANGMAN_LIST_DELETE_ITEM' | translate }}"
+            ng-click='removeListElem(currentDisplayIndex + offset,true)'></button>
+
+    <!-- duplicate indicator -->
+    <button class="yangButton iconDanger"
+            tooltip="{{ 'YANGMAN_LIST_INDEX_DUPLICATE' | translate }}"
+            ng-show="node.doubleKeyIndexes.indexOf(currentDisplayIndex + offset)>-1"></button>
+</div>
+
+<!-- next item button -->
+<button ng-click="shiftDisplayNext('filteredListData')"
+        ng-show="showNextButton('filteredListData')"
+        tooltip="{{ 'YANGMAN_LIST_NEXT_ITEM' | translate }}"
+        class="yangButton iconNext"></button>
diff --git a/modules/yangman-resources/src/main/resources/yangman/views/rightpanel/form/config/list.tpl.html b/modules/yangman-resources/src/main/resources/yangman/views/rightpanel/form/config/list.tpl.html
new file mode 100644 (file)
index 0000000..171617f
--- /dev/null
@@ -0,0 +1,52 @@
+<div ng-controller="YMListCtrl as yangList"
+     class="yangmanModule__right-panel__form__element-container"
+     ng-class="{'expanded' : node.expanded}"
+     ng-init="yangList.init()">
+
+    <!-- container title -->
+    <div layout="row"
+         layout-align="start center"
+         class="container-label">
+
+        <!-- Expand Icon -->
+        <md-icon md-font-set="material-icons" class="top-icon top-element pointer" ng-click="yangList.toggleExpanded()">
+            <md-tooltip md-direction="left">{{ 'YANGMAN_SHOW_HIDE_CON' | translate }}</md-tooltip>
+            {{node.expanded ? 'keyboard_arrow_down':'keyboard_arrow_right'}}
+        </md-icon>
+
+        <!-- list label -->
+        <p class="top-element pointer list-label" ng-click="yangList.toggleExpanded()" ym-info-box node="node">
+            {{yangForm.getNodeName(node.localeLabel, node.label)}}
+        </p>
+
+        <!-- Action menu -->
+        <yang-form-menu is-action-menu="yangList.isActionMenu()"
+                        augmentations="augmentations"
+                        add-list-item-func="yangList.addListElem()"
+                        add-list-item="!yangList.disableAddingListElement"
+                        yang-form="yangForm"
+                        yang-list="yangList"
+                        node="node"></yang-form-menu>
+
+        <!--<ng-include src="currentPath+'/filter.tpl.html'"></ng-include>-->
+
+        <section layout="row"
+                 layout-align="start center"
+                 class="yangmanModule__right-panel__form__list__paginator"
+                 ng-include="yangForm.viewPath + '/list-data-top.tpl.html'"
+                 ng-if="!(node.filteredListData && node.filteredListData.length)"></section>
+
+        <div class="listItemWrapper"
+             ng-include="yangForm.viewPath + '/config/list-filtered-data-top.tpl.html'"
+             ng-if="(node.filteredListData && node.filteredListData.length)"></div>
+
+    </div>
+
+    <!-- list's children -->
+    <div ng-if="node.actElemStructure" ng-show="node.expanded">
+        <div ng-repeat="node in node.actElemStructure.getChildren(null,null,constants.NODE_UI_DISPLAY) | ymOnlyConfigElem"
+             ng-include="yangForm.viewPath + '/config/' + node.type+'.tpl.html'"
+             ng-hide="node.augmentationId && !augmentations.getAugmentation(node.parent, node.augmentationId).expanded">
+        </div>
+    </div>
+</div>
diff --git a/modules/yangman-resources/src/main/resources/yangman/views/rightpanel/form/config/output.tpl.html b/modules/yangman-resources/src/main/resources/yangman/views/rightpanel/form/config/output.tpl.html
new file mode 100644 (file)
index 0000000..cb86b83
--- /dev/null
@@ -0,0 +1,34 @@
+<div ng-controller="YMOutputCtrl as yangOutput"
+     class="yangmanModule__right-panel__form__element-container"
+     ng-class="{'expanded' : node.expanded}">
+
+    <!-- container title -->
+    <div layout="row"
+         layout-align="start center"
+         class="pointer container-label"
+         ng-click="yangOutput.toggleExpanded()">
+
+        <!-- Expand Icon -->
+        <md-icon md-font-set="material-icons" class="top-icon top-element">
+            <md-tooltip md-direction="left">{{ 'YANGMAN_SHOW_HIDE_CON' | translate }}</md-tooltip>
+            {{node.expanded ? 'keyboard_arrow_down':'keyboard_arrow_right'}}
+        </md-icon>
+
+        <!-- Container label -->
+        <p class="top-element" ym-info-box node="node"> {{yangForm.getNodeName(node.localeLabel, node.label)}} </p>
+
+        <!-- Action menu -->
+        <yang-form-menu is-action-menu="yangOutput.isActionMenu()"
+                        augmentations="augmentations"
+                        node="node"></yang-form-menu>
+
+    </div>
+
+    <!-- output's children -->
+    <div ng-if="node.expanded">
+        <div ng-repeat="node in node.getChildren(null,null,constants.NODE_UI_DISPLAY) | ymOnlyConfigElem"
+             ng-include="yangForm.viewPath + '/config/' + node.type+'.tpl.html'"
+             ng-hide="node.augmentationId && !augmentations.getAugmentation(node.parent, node.augmentationId).expanded">
+        </div>
+    </div>
+</div>
diff --git a/modules/yangman-resources/src/main/resources/yangman/views/rightpanel/form/config/rpc.tpl.html b/modules/yangman-resources/src/main/resources/yangman/views/rightpanel/form/config/rpc.tpl.html
new file mode 100644 (file)
index 0000000..30e8c2a
--- /dev/null
@@ -0,0 +1,32 @@
+<div ng-controller="YMRpcCtrl as yangRpc"
+     class="yangmanModule__right-panel__form__element-container"
+     ng-class="{'expanded' : node.expanded}">
+
+    <!-- container title -->
+    <div layout="row"
+         layout-align="start center"
+         class="pointer container-label"
+         ng-click="yangRpc.toggleExpanded()">
+
+        <!-- Expand Icon -->
+        <md-icon md-font-set="material-icons" class="top-icon top-element">
+            <md-tooltip md-direction="left">{{ 'YANGMAN_SHOW_HIDE_CON' | translate }}</md-tooltip>
+            {{node.expanded ? 'keyboard_arrow_down':'keyboard_arrow_right'}}
+        </md-icon>
+
+        <!-- Container label -->
+        <p class="top-element" ym-info-box node="node"> {{yangForm.getNodeName(node.localeLabel, node.label)}} </p>
+
+        <!-- Action menu -->
+        <yang-form-menu is-action-menu="yangRpc.isActionMenu()"
+                        augmentations="augmentations"
+                        node="node"></yang-form-menu>
+
+    </div>
+
+    <!-- Rpc's children -->
+    <div ng-if="node.expanded">
+        <div ng-repeat="node in node.getChildren(null,null,constants.NODE_UI_DISPLAY) | ymOnlyConfigElem"
+             ng-include="yangForm.viewPath + '/config/' + node.type + '.tpl.html'"></div>
+    </div>
+</div>
diff --git a/modules/yangman-resources/src/main/resources/yangman/views/rightpanel/form/config/types/binary.tpl.html b/modules/yangman-resources/src/main/resources/yangman/views/rightpanel/form/config/types/binary.tpl.html
new file mode 100644 (file)
index 0000000..e0d57ae
--- /dev/null
@@ -0,0 +1,9 @@
+<md-input-container md-no-float>
+    <input ng-change="yangType.valueChanged()" ng-model="node.value" aria-label="{{node.value}}" placeholder="{{type.label}}" ng-disabled="{{ yangOutput.notEditable }}">
+    <md-tooltip md-direction="top">{{type.label}}</md-tooltip>
+</md-input-container>
+
+<md-icon md-font-set="material-icons" class="top-icon top-element pointer" ng-show="type.errors.length > 0">
+    <md-tooltip md-direction="top">{{type.errors.join('\n')}}</md-tooltip>
+    error_outline
+</md-icon>
\ No newline at end of file
diff --git a/modules/yangman-resources/src/main/resources/yangman/views/rightpanel/form/config/types/bits.tpl.html b/modules/yangman-resources/src/main/resources/yangman/views/rightpanel/form/config/types/bits.tpl.html
new file mode 100644 (file)
index 0000000..382b119
--- /dev/null
@@ -0,0 +1,17 @@
+<section ng-controller="YMTypeBitCtrl as yangTypeBit"
+         layout="row"
+         flex="50"
+         class="md-whiteframe-z2 box-container"
+         layout-wrap
+         layout-padding>
+
+    <md-checkbox ng-model="type.bitsValues[$index]"
+                 ng-repeat="bit in type.getChildren('bit')"
+                 ng-true-value="1"
+                 ng-false-value="0"
+                 ng-change="yangTypeBit.valueChanged()"
+                 ng-disabled="{{ yangOutput.notEditable }}"
+                 aria-label="{{bit.label}}">
+        {{bit.label}}
+    </md-checkbox>
+</section>
diff --git a/modules/yangman-resources/src/main/resources/yangman/views/rightpanel/form/config/types/boolean.tpl.html b/modules/yangman-resources/src/main/resources/yangman/views/rightpanel/form/config/types/boolean.tpl.html
new file mode 100644 (file)
index 0000000..fd564b4
--- /dev/null
@@ -0,0 +1,9 @@
+<section ng-controller="YMTypeBooleanCtrl as yangTypeBolean" layout="row" class="layout-row flex-center" flex>
+       <span class="mr8">F</span>
+    <md-switch ng-model="node.value"
+               id="{{ node.label + node.id }}"
+               aria-label="Boolean"
+               ng-disabled="{{ yangOutput.notEditable }}">
+    </md-switch>
+    <span>T</span>
+</section>
diff --git a/modules/yangman-resources/src/main/resources/yangman/views/rightpanel/form/config/types/decimal64.tpl.html b/modules/yangman-resources/src/main/resources/yangman/views/rightpanel/form/config/types/decimal64.tpl.html
new file mode 100644 (file)
index 0000000..e0d57ae
--- /dev/null
@@ -0,0 +1,9 @@
+<md-input-container md-no-float>
+    <input ng-change="yangType.valueChanged()" ng-model="node.value" aria-label="{{node.value}}" placeholder="{{type.label}}" ng-disabled="{{ yangOutput.notEditable }}">
+    <md-tooltip md-direction="top">{{type.label}}</md-tooltip>
+</md-input-container>
+
+<md-icon md-font-set="material-icons" class="top-icon top-element pointer" ng-show="type.errors.length > 0">
+    <md-tooltip md-direction="top">{{type.errors.join('\n')}}</md-tooltip>
+    error_outline
+</md-icon>
\ No newline at end of file
diff --git a/modules/yangman-resources/src/main/resources/yangman/views/rightpanel/form/config/types/default.tpl.html b/modules/yangman-resources/src/main/resources/yangman/views/rightpanel/form/config/types/default.tpl.html
new file mode 100644 (file)
index 0000000..6029668
--- /dev/null
@@ -0,0 +1,10 @@
+<md-input-container md-no-float>
+    <input ng-change="yangType.valueChanged()" ng-model="node.value" aria-label="{{node.value}}" placeholder="{{type.label}}" ng-disabled="{{ yangOutput.notEditable }}">
+    <md-tooltip md-direction="top">{{type.label}}</md-tooltip>
+</md-input-container>
+
+<md-icon md-font-set="material-icons" class="top-icon top-element pointer" ng-show="type.errors.length > 0">
+    <md-tooltip md-direction="top">{{type.errors.join('\n')}}</md-tooltip>
+    error_outline
+</md-icon>
+
diff --git a/modules/yangman-resources/src/main/resources/yangman/views/rightpanel/form/config/types/empty.tpl.html b/modules/yangman-resources/src/main/resources/yangman/views/rightpanel/form/config/types/empty.tpl.html
new file mode 100644 (file)
index 0000000..b4fa124
--- /dev/null
@@ -0,0 +1,14 @@
+<section ng-controller="YMTypeEmptyCtrl as yangTypeEmpty"
+         layout="row"
+         flex="50"
+         class="md-whiteframe-z2 box-container"
+         layout-wrap
+         layout-padding>
+
+    <md-checkbox ng-model="type.emptyValue"
+                 ng-true-value="1"
+                 ng-false-value="0"
+                 ng-change="yangTypeEmpty.valueChanged()"
+                 ng-disabled="{{ yangOutput.notEditable }}"
+                 aria-label="{{type.label}}"></md-checkbox>
+</section>
diff --git a/modules/yangman-resources/src/main/resources/yangman/views/rightpanel/form/config/types/enumeration.tpl.html b/modules/yangman-resources/src/main/resources/yangman/views/rightpanel/form/config/types/enumeration.tpl.html
new file mode 100644 (file)
index 0000000..4a1826f
--- /dev/null
@@ -0,0 +1,7 @@
+<md-input-container ng-controller="YMTypeEnumCtrl as yangTypeEnum">
+    <md-select ng-model="type.selEnum" md-on-close="yangTypeEnum.valueChanged()" ng-disabled="{{ yangOutput.notEditable }}">
+        <md-option ng-repeat="enum in type.getChildren('enum')" ng-value="enum">
+            {{enum.label}}
+        </md-option>
+    </md-select>
+</md-input-container>
diff --git a/modules/yangman-resources/src/main/resources/yangman/views/rightpanel/form/config/types/identityref.tpl.html b/modules/yangman-resources/src/main/resources/yangman/views/rightpanel/form/config/types/identityref.tpl.html
new file mode 100644 (file)
index 0000000..d40379e
--- /dev/null
@@ -0,0 +1,4 @@
+<md-input-container md-no-float>
+    <input ng-change="yangType.valueChanged()" ng-model="node.value" aria-label="{{node.value}}" placeholder="{{type.label}}" ng-disabled="{{ yangOutput.notEditable }}">
+    <md-tooltip md-direction="top">{{type.label}}</md-tooltip>
+</md-input-container>
\ No newline at end of file
diff --git a/modules/yangman-resources/src/main/resources/yangman/views/rightpanel/form/config/types/instance-identifier.tpl.html b/modules/yangman-resources/src/main/resources/yangman/views/rightpanel/form/config/types/instance-identifier.tpl.html
new file mode 100644 (file)
index 0000000..e0d57ae
--- /dev/null
@@ -0,0 +1,9 @@
+<md-input-container md-no-float>
+    <input ng-change="yangType.valueChanged()" ng-model="node.value" aria-label="{{node.value}}" placeholder="{{type.label}}" ng-disabled="{{ yangOutput.notEditable }}">
+    <md-tooltip md-direction="top">{{type.label}}</md-tooltip>
+</md-input-container>
+
+<md-icon md-font-set="material-icons" class="top-icon top-element pointer" ng-show="type.errors.length > 0">
+    <md-tooltip md-direction="top">{{type.errors.join('\n')}}</md-tooltip>
+    error_outline
+</md-icon>
\ No newline at end of file
diff --git a/modules/yangman-resources/src/main/resources/yangman/views/rightpanel/form/config/types/int16.tpl.html b/modules/yangman-resources/src/main/resources/yangman/views/rightpanel/form/config/types/int16.tpl.html
new file mode 100644 (file)
index 0000000..e0d57ae
--- /dev/null
@@ -0,0 +1,9 @@
+<md-input-container md-no-float>
+    <input ng-change="yangType.valueChanged()" ng-model="node.value" aria-label="{{node.value}}" placeholder="{{type.label}}" ng-disabled="{{ yangOutput.notEditable }}">
+    <md-tooltip md-direction="top">{{type.label}}</md-tooltip>
+</md-input-container>
+
+<md-icon md-font-set="material-icons" class="top-icon top-element pointer" ng-show="type.errors.length > 0">
+    <md-tooltip md-direction="top">{{type.errors.join('\n')}}</md-tooltip>
+    error_outline
+</md-icon>
\ No newline at end of file
diff --git a/modules/yangman-resources/src/main/resources/yangman/views/rightpanel/form/config/types/int32.tpl.html b/modules/yangman-resources/src/main/resources/yangman/views/rightpanel/form/config/types/int32.tpl.html
new file mode 100644 (file)
index 0000000..e0d57ae
--- /dev/null
@@ -0,0 +1,9 @@
+<md-input-container md-no-float>
+    <input ng-change="yangType.valueChanged()" ng-model="node.value" aria-label="{{node.value}}" placeholder="{{type.label}}" ng-disabled="{{ yangOutput.notEditable }}">
+    <md-tooltip md-direction="top">{{type.label}}</md-tooltip>
+</md-input-container>
+
+<md-icon md-font-set="material-icons" class="top-icon top-element pointer" ng-show="type.errors.length > 0">
+    <md-tooltip md-direction="top">{{type.errors.join('\n')}}</md-tooltip>
+    error_outline
+</md-icon>
\ No newline at end of file
diff --git a/modules/yangman-resources/src/main/resources/yangman/views/rightpanel/form/config/types/int64.tpl.html b/modules/yangman-resources/src/main/resources/yangman/views/rightpanel/form/config/types/int64.tpl.html
new file mode 100644 (file)
index 0000000..e0d57ae
--- /dev/null
@@ -0,0 +1,9 @@
+<md-input-container md-no-float>
+    <input ng-change="yangType.valueChanged()" ng-model="node.value" aria-label="{{node.value}}" placeholder="{{type.label}}" ng-disabled="{{ yangOutput.notEditable }}">
+    <md-tooltip md-direction="top">{{type.label}}</md-tooltip>
+</md-input-container>
+
+<md-icon md-font-set="material-icons" class="top-icon top-element pointer" ng-show="type.errors.length > 0">
+    <md-tooltip md-direction="top">{{type.errors.join('\n')}}</md-tooltip>
+    error_outline
+</md-icon>
\ No newline at end of file
diff --git a/modules/yangman-resources/src/main/resources/yangman/views/rightpanel/form/config/types/int8.tpl.html b/modules/yangman-resources/src/main/resources/yangman/views/rightpanel/form/config/types/int8.tpl.html
new file mode 100644 (file)
index 0000000..e0d57ae
--- /dev/null
@@ -0,0 +1,9 @@
+<md-input-container md-no-float>
+    <input ng-change="yangType.valueChanged()" ng-model="node.value" aria-label="{{node.value}}" placeholder="{{type.label}}" ng-disabled="{{ yangOutput.notEditable }}">
+    <md-tooltip md-direction="top">{{type.label}}</md-tooltip>
+</md-input-container>
+
+<md-icon md-font-set="material-icons" class="top-icon top-element pointer" ng-show="type.errors.length > 0">
+    <md-tooltip md-direction="top">{{type.errors.join('\n')}}</md-tooltip>
+    error_outline
+</md-icon>
\ No newline at end of file
diff --git a/modules/yangman-resources/src/main/resources/yangman/views/rightpanel/form/config/types/leafref.tpl.html b/modules/yangman-resources/src/main/resources/yangman/views/rightpanel/form/config/types/leafref.tpl.html
new file mode 100644 (file)
index 0000000..d40379e
--- /dev/null
@@ -0,0 +1,4 @@
+<md-input-container md-no-float>
+    <input ng-change="yangType.valueChanged()" ng-model="node.value" aria-label="{{node.value}}" placeholder="{{type.label}}" ng-disabled="{{ yangOutput.notEditable }}">
+    <md-tooltip md-direction="top">{{type.label}}</md-tooltip>
+</md-input-container>
\ No newline at end of file
diff --git a/modules/yangman-resources/src/main/resources/yangman/views/rightpanel/form/config/types/string.tpl.html b/modules/yangman-resources/src/main/resources/yangman/views/rightpanel/form/config/types/string.tpl.html
new file mode 100644 (file)
index 0000000..e0d57ae
--- /dev/null
@@ -0,0 +1,9 @@
+<md-input-container md-no-float>
+    <input ng-change="yangType.valueChanged()" ng-model="node.value" aria-label="{{node.value}}" placeholder="{{type.label}}" ng-disabled="{{ yangOutput.notEditable }}">
+    <md-tooltip md-direction="top">{{type.label}}</md-tooltip>
+</md-input-container>
+
+<md-icon md-font-set="material-icons" class="top-icon top-element pointer" ng-show="type.errors.length > 0">
+    <md-tooltip md-direction="top">{{type.errors.join('\n')}}</md-tooltip>
+    error_outline
+</md-icon>
\ No newline at end of file
diff --git a/modules/yangman-resources/src/main/resources/yangman/views/rightpanel/form/config/types/uint16.tpl.html b/modules/yangman-resources/src/main/resources/yangman/views/rightpanel/form/config/types/uint16.tpl.html
new file mode 100644 (file)
index 0000000..e0d57ae
--- /dev/null
@@ -0,0 +1,9 @@
+<md-input-container md-no-float>
+    <input ng-change="yangType.valueChanged()" ng-model="node.value" aria-label="{{node.value}}" placeholder="{{type.label}}" ng-disabled="{{ yangOutput.notEditable }}">
+    <md-tooltip md-direction="top">{{type.label}}</md-tooltip>
+</md-input-container>
+
+<md-icon md-font-set="material-icons" class="top-icon top-element pointer" ng-show="type.errors.length > 0">
+    <md-tooltip md-direction="top">{{type.errors.join('\n')}}</md-tooltip>
+    error_outline
+</md-icon>
\ No newline at end of file
diff --git a/modules/yangman-resources/src/main/resources/yangman/views/rightpanel/form/config/types/uint32.tpl.html b/modules/yangman-resources/src/main/resources/yangman/views/rightpanel/form/config/types/uint32.tpl.html
new file mode 100644 (file)
index 0000000..e0d57ae
--- /dev/null
@@ -0,0 +1,9 @@
+<md-input-container md-no-float>
+    <input ng-change="yangType.valueChanged()" ng-model="node.value" aria-label="{{node.value}}" placeholder="{{type.label}}" ng-disabled="{{ yangOutput.notEditable }}">
+    <md-tooltip md-direction="top">{{type.label}}</md-tooltip>
+</md-input-container>
+
+<md-icon md-font-set="material-icons" class="top-icon top-element pointer" ng-show="type.errors.length > 0">
+    <md-tooltip md-direction="top">{{type.errors.join('\n')}}</md-tooltip>
+    error_outline
+</md-icon>
\ No newline at end of file
diff --git a/modules/yangman-resources/src/main/resources/yangman/views/rightpanel/form/config/types/uint64.tpl.html b/modules/yangman-resources/src/main/resources/yangman/views/rightpanel/form/config/types/uint64.tpl.html
new file mode 100644 (file)
index 0000000..e0d57ae
--- /dev/null
@@ -0,0 +1,9 @@
+<md-input-container md-no-float>
+    <input ng-change="yangType.valueChanged()" ng-model="node.value" aria-label="{{node.value}}" placeholder="{{type.label}}" ng-disabled="{{ yangOutput.notEditable }}">
+    <md-tooltip md-direction="top">{{type.label}}</md-tooltip>
+</md-input-container>
+
+<md-icon md-font-set="material-icons" class="top-icon top-element pointer" ng-show="type.errors.length > 0">
+    <md-tooltip md-direction="top">{{type.errors.join('\n')}}</md-tooltip>
+    error_outline
+</md-icon>
\ No newline at end of file
diff --git a/modules/yangman-resources/src/main/resources/yangman/views/rightpanel/form/config/types/uint8.tpl.html b/modules/yangman-resources/src/main/resources/yangman/views/rightpanel/form/config/types/uint8.tpl.html
new file mode 100644 (file)
index 0000000..e0d57ae
--- /dev/null
@@ -0,0 +1,9 @@
+<md-input-container md-no-float>
+    <input ng-change="yangType.valueChanged()" ng-model="node.value" aria-label="{{node.value}}" placeholder="{{type.label}}" ng-disabled="{{ yangOutput.notEditable }}">
+    <md-tooltip md-direction="top">{{type.label}}</md-tooltip>
+</md-input-container>
+
+<md-icon md-font-set="material-icons" class="top-icon top-element pointer" ng-show="type.errors.length > 0">
+    <md-tooltip md-direction="top">{{type.errors.join('\n')}}</md-tooltip>
+    error_outline
+</md-icon>
\ No newline at end of file
diff --git a/modules/yangman-resources/src/main/resources/yangman/views/rightpanel/form/config/types/union.tpl.html b/modules/yangman-resources/src/main/resources/yangman/views/rightpanel/form/config/types/union.tpl.html
new file mode 100644 (file)
index 0000000..7a8ae66
--- /dev/null
@@ -0,0 +1,18 @@
+<md-content flex="nogrow" md-whiteframe="2" class="box-container union">
+    <md-tabs md-dynamic-height
+             md-border-bottom
+             md-no-pagination
+             md-stretch-tabs="always"
+             class="union-tabs">
+        <md-tab ng-repeat="type in type.getChildren('type') track by $index">
+            <md-tab-label>
+                <!--<md-tooltip md-direction="top">{{type.label}}</md-tooltip>-->
+                {{type.label}}
+            </md-tab-label>
+            <md-tab-body>
+                <md-content class="md-padding"
+                            ng-include="yangForm.viewPath + '/config/types/' + type.label + '.tpl.html'"></md-content>
+            </md-tab-body>
+        </md-tab>
+    </md-tabs>
+</md-content>
diff --git a/modules/yangman-resources/src/main/resources/yangman/views/rightpanel/form/list-data-top.tpl.html b/modules/yangman-resources/src/main/resources/yangman/views/rightpanel/form/list-data-top.tpl.html
new file mode 100644 (file)
index 0000000..6831c05
--- /dev/null
@@ -0,0 +1,52 @@
+<!-- Previous button -->
+<button ng-click="yangList.shiftDisplayPrev()"
+        ng-show="yangList.showPrevButton()">
+    <md-icon class="material-icons">{{yangList.showPrevButton() ? 'arrow_back' : ''}}</md-icon>
+    <md-tooltip md-direction="top">{{ 'YANGMAN_LIST_PREV_ITEM' | translate }}</md-tooltip>
+</button>
+
+<section ng-repeat="offset in yangList.displayOffsets" class="yangmanModule__right-panel__form__list-item"
+         layout="row" layout-align="start center"
+         ng-if="yangList.currentDisplayIndex + offset > -1 && node.listData.length > yangList.currentDisplayIndex + offset">
+
+    <!-- label -->
+    <md-tab-item class="md-tab pointer" ng-click="node.changeActElementData(yangList.currentDisplayIndex + offset)"
+                 ng-class="{'': yangList.currentDisplayIndex + offset === node.actElemIndex}">
+        <div layout="row">
+            <span flex="grow">
+                {{yangForm.getNodeName(node.localeLabel, node.label)}}&nbsp;{{ yangList.getListName(offset, true).name }}
+            </span>
+        </div>
+
+        <md-tooltip md-direction="top" ng-if="yangList.getListName(offset, false).tooltip.length">
+            {{yangList.getListName(offset, false).tooltip}}
+        </md-tooltip>
+
+        <md-ink-bar class="custom" ng-if="yangList.currentDisplayIndex + offset === node.actElemIndex"></md-ink-bar>
+    </md-tab-item>
+
+    <!-- remove button -->
+    <md-icon md-font-set="material-icons"
+             class="pointer"
+             ng-click="yangList.removeListElem(yangList.currentDisplayIndex + offset,false)"
+             ng-if="(selectedDatastore.label === yangList.constants.DATA_STORE_CONFIG ||
+                    selectedDatastore.label === yangList.constants.DATA_STORE_OPERATIONS) && !yangList.disableAddingListElement">
+        <md-tooltip md-direction="top">{{ 'YANGMAN_LIST_DELETE_ITEM' | translate }}</md-tooltip>
+        remove_circle_outline
+    </md-icon>
+
+    <!-- duplicated key -->
+    <md-icon md-font-set="material-icons"
+             ng-show="node.doubleKeyIndexes.indexOf(yangList.currentDisplayIndex + offset) > -1"
+             ng-if="selectedDatastore.label === yangList.constants.DATA_STORE_CONFIG">
+        <md-tooltip md-direction="top">{{ 'YANGMAN_LIST_INDEX_DUPLICATE' | translate }}</md-tooltip>
+        error_outline
+    </md-icon>
+</section>
+
+<!-- Next button -->
+<button ng-click="yangList.shiftDisplayNext('listData')"
+        ng-show="yangList.showNextButton('listData')">
+    <md-icon class="material-icons">arrow_forward</md-icon>
+    <md-tooltip md-direction="top">{{ 'YANGMAN_LIST_NEXT_ITEM' | translate }}</md-tooltip>
+</button>
diff --git a/modules/yangman-resources/src/main/resources/yangman/views/rightpanel/form/operational/case.tpl.html b/modules/yangman-resources/src/main/resources/yangman/views/rightpanel/form/operational/case.tpl.html
new file mode 100644 (file)
index 0000000..3f51030
--- /dev/null
@@ -0,0 +1,5 @@
+<div ng-controller="YMCaseCtrl as yangCase" ng-show="case.isFilled() && yangCase.empty">
+    <!-- case's children -->
+    <div ng-repeat="node in case.getChildren(null,null,constants.NODE_UI_DISPLAY)"
+         ng-include="yangForm.viewPath + '/operational/' + node.type + '.tpl.html'"></div>
+</div>
diff --git a/modules/yangman-resources/src/main/resources/yangman/views/rightpanel/form/operational/choice.tpl.html b/modules/yangman-resources/src/main/resources/yangman/views/rightpanel/form/operational/choice.tpl.html
new file mode 100644 (file)
index 0000000..eef1c33
--- /dev/null
@@ -0,0 +1,38 @@
+<div ng-controller="YMChoiceCtrl as yangChoice"
+     class="yangmanModule__right-panel__form__element-container"
+     ng-class="{'expanded' : node.expanded}"
+     ng-show="node.isFilled()">
+
+    <!-- choice title -->
+    <div layout="row"
+         layout-align="start center"
+         class="pointer container-label">
+
+        <!-- Expand Icon -->
+        <md-icon md-font-set="material-icons" class="top-icon top-element" ng-click="yangChoice.toggleExpanded()">
+            <md-tooltip md-direction="left">{{ 'YANGMAN_SHOW_HIDE_CON' | translate }}</md-tooltip>
+            {{node.expanded ? 'keyboard_arrow_down':'keyboard_arrow_right'}}
+        </md-icon>
+
+        <!-- Choice label -->
+        <p class="top-element" ym-info-box node="node" ng-click="yangChoice.toggleExpanded()">
+            {{yangForm.getNodeName(node.localeLabel, node.label)}}
+        </p>
+
+        <!-- Action menu -->
+        <yang-form-menu is-action-menu="yangChoice.isActionMenu()"
+                        augmentations="augmentations"
+                        node="node"></yang-form-menu>
+
+        <!-- Choice select -->
+        <md-input-container>
+            <input ng-model="node.choice.label" aria-label="{{node.choice.label}}" ng-disabled="true">
+        </md-input-container>
+    </div>
+
+    <!-- choice's children -->
+    <div ng-repeat="case in node.getChildren(null,null,constants.NODE_UI_DISPLAY)"
+         ng-include="yangForm.viewPath + '/operational/' + case.type +'.tpl.html'"
+         ng-show="node.choice.id === case.id && node.expanded"
+         ng-if="!(case.augmentationId && !augmentations.getAugmentation(case.parent, case.augmentationId).expanded)"></div>
+</div>
diff --git a/modules/yangman-resources/src/main/resources/yangman/views/rightpanel/form/operational/container.tpl.html b/modules/yangman-resources/src/main/resources/yangman/views/rightpanel/form/operational/container.tpl.html
new file mode 100644 (file)
index 0000000..066b2e4
--- /dev/null
@@ -0,0 +1,38 @@
+<div ng-controller="YMContainerCtrl as yangContainer"
+     class="yangmanModule__right-panel__form__element-container"
+     ng-class="{'expanded' : node.expanded}"
+     ng-show="node.isFilled()">
+
+    <!-- container title -->
+    <div layout="row"
+         layout-align="start center"
+         class="pointer container-label">
+
+        <!-- Expand Icon -->
+        <md-icon md-font-set="material-icons"
+                 class="top-icon top-element pointer"
+                 ng-click="yangContainer.toggleExpanded()">
+            <md-tooltip md-direction="left">{{ 'YANGMAN_SHOW_HIDE_CON' | translate }}</md-tooltip>
+            {{node.expanded ? 'keyboard_arrow_down':'keyboard_arrow_right'}}
+        </md-icon>
+
+        <!-- Container label -->
+        <p class="top-element pointer" ng-click="yangContainer.toggleExpanded()" ym-info-box node="node">
+            {{yangForm.getNodeName(node.localeLabel, node.label)}}
+        </p>
+
+        <!-- Action menu -->
+        <yang-form-menu is-action-menu="yangContainer.isActionMenu()"
+                        augmentations="augmentations"
+                        node="node"></yang-form-menu>
+
+    </div>
+
+    <!-- container's children -->
+    <div ng-if="node.expanded">
+        <div ng-repeat="node in node.getChildren(null,null,constants.NODE_UI_DISPLAY)"
+             ng-include="yangForm.viewPath + '/operational/' + node.type+'.tpl.html'"
+             ng-hide="node.augmentationId && !augmentations.getAugmentation(node.parent, node.augmentationId).expanded">
+        </div>
+    </div>
+</div>
diff --git a/modules/yangman-resources/src/main/resources/yangman/views/rightpanel/form/operational/input.tpl.html b/modules/yangman-resources/src/main/resources/yangman/views/rightpanel/form/operational/input.tpl.html
new file mode 100644 (file)
index 0000000..617e2f4
--- /dev/null
@@ -0,0 +1,35 @@
+<div ng-controller="YMInputCtrl as yangInput"
+     class="yangmanModule__right-panel__form__element-container"
+     ng-class="{'expanded' : node.expanded}"
+     ng-show="node.isFilled()">
+
+    <!-- container title -->
+    <div layout="row"
+         layout-align="start center"
+         class="pointer container-label"
+         ng-click="yangInput.toggleExpanded()">
+
+        <!-- Expand Icon -->
+        <md-icon md-font-set="material-icons" class="top-icon top-element">
+            <md-tooltip md-direction="left">{{ 'YANGMAN_SHOW_HIDE_CON' | translate }}</md-tooltip>
+            {{node.expanded ? 'keyboard_arrow_down':'keyboard_arrow_right'}}
+        </md-icon>
+
+        <!-- Container label -->
+        <p class="top-element" ym-info-box node="node"> {{yangForm.getNodeName(node.localeLabel, node.label)}} </p>
+
+        <!-- Action menu -->
+        <yang-form-menu is-action-menu="yangInput.isActionMenu()"
+                        augmentations="augmentations"
+                        node="node"></yang-form-menu>
+
+    </div>
+
+    <!-- output's children -->
+    <div ng-if="node.expanded">
+        <div ng-repeat="node in node.getChildren(null,null,constants.NODE_UI_DISPLAY)"
+             ng-include="yangForm.viewPath + '/operational/' + node.type+'.tpl.html'"
+             ng-hide="node.augmentationId && !augmentations.getAugmentation(node.parent, node.augmentationId).expanded">
+        </div>
+    </div>
+</div>
diff --git a/modules/yangman-resources/src/main/resources/yangman/views/rightpanel/form/operational/leaf-list.tpl.html b/modules/yangman-resources/src/main/resources/yangman/views/rightpanel/form/operational/leaf-list.tpl.html
new file mode 100644 (file)
index 0000000..b2bba79
--- /dev/null
@@ -0,0 +1,35 @@
+<div ng-controller="YMLeafListCtrl as yangLeafList"
+     class="yangmanModule__right-panel__form__element-container"
+     ng-class="{'expanded' : node.expanded}"
+     ng-show="node.isFilled()">
+
+    <!-- container title -->
+    <div layout="row"
+         layout-align="start center"
+         class="pointer container-label">
+
+        <!-- Expand Icon -->
+        <md-icon md-font-set="material-icons" class="top-icon top-element" ng-click="yangLeafList.toggleExpanded()">
+            <md-tooltip md-direction="left">{{ 'YANGMAN_SHOW_HIDE_CON' | translate }}</md-tooltip>
+            {{node.expanded ? 'keyboard_arrow_down':'keyboard_arrow_right'}}
+        </md-icon>
+
+        <!-- Container label -->
+        <p class="top-element" ym-info-box node="node" ng-click="yangLeafList.toggleExpanded()">
+            {{yangForm.getNodeName(node.localeLabel, node.label)}}
+        </p>
+
+        <!-- Action menu -->
+        <yang-form-menu is-action-menu="yangLeafList.isActionMenu()"
+                        augmentations="augmentations"
+                        node="node"></yang-form-menu>
+    </div>
+
+    <div ng-repeat="elem in node.value" ng-show="node.expanded">
+        <!-- Leaf list values -->
+        <md-input-container md-no-float  class="input-icon-container">
+            <!-- input -->
+            <input ng-model="elem.value" aria-label="{{elem.value}}" ng-disabled="true">
+        </md-input-container>
+    </div>
+</div>
diff --git a/modules/yangman-resources/src/main/resources/yangman/views/rightpanel/form/operational/leaf.tpl.html b/modules/yangman-resources/src/main/resources/yangman/views/rightpanel/form/operational/leaf.tpl.html
new file mode 100644 (file)
index 0000000..ca34070
--- /dev/null
@@ -0,0 +1,21 @@
+<div ng-controller="YMLeafCtrl as yanfLeaf"
+     layout="row"
+     layout-align="start center"
+     class="yangmanModule__right-panel__form__leaf-container"
+     ng-show="node.isFilled()">
+
+    <!-- Container label -->
+    <p class="top-element" ym-info-box node="node"> {{yangForm.getNodeName(node.localeLabel, node.label)}} </p>
+
+    <!-- Action menu -->
+    <yang-form-menu is-action-menu="yanfLeaf.isActionMenu()"
+                    augmentations="augmentations"
+                    node="node"></yang-form-menu>
+
+    <!-- Empty placeholder for better look -->
+    <div class="menu-placeholder" ng-if="!yanfLeaf.isActionMenu() && !yanfLeaf.isNodeInfo()"></div>
+
+    <md-input-container>
+        <input ng-model="node.value" aria-label="{{node.value}}" ng-disabled="true">
+    </md-input-container>
+</div>
diff --git a/modules/yangman-resources/src/main/resources/yangman/views/rightpanel/form/operational/list-filtered-data-top.tpl.html b/modules/yangman-resources/src/main/resources/yangman/views/rightpanel/form/operational/list-filtered-data-top.tpl.html
new file mode 100644 (file)
index 0000000..bd5fa92
--- /dev/null
@@ -0,0 +1,23 @@
+<!-- previous item button -->
+<button ng-click="shiftDisplayPrev()"
+        ng-show="showPrevButton()"
+        tooltip="{{ 'YANGMAN_LIST_PREV_ITEM' | translate }}"
+        class="yangButton iconPrev"></button>
+
+<!-- item list -->
+<div class="listButtonWrapper"
+     ng-repeat="offset in displayOffsets"
+     ng-if="currentDisplayIndex + offset > -1 && node.filteredListData.length > currentDisplayIndex + offset">
+
+    <button  class="btn btn-like-tab {{ (currentDisplayIndex + offset === node.actElemIndex ? 'btn-selected':'') }}"
+             ng-click="node.changeActElementData(currentDisplayIndex + offset,false)"
+             tooltip="{{getListName(offset, false).tooltip}}">
+        {{yangForm.getNodeName(node.localeLabel, node.label)}}&nbsp;{{ getListName(offset, true).name }}
+    </button>
+</div>
+
+<!-- next item button -->
+<button ng-click="shiftDisplayNext('filteredListData')"
+        ng-show="showNextButton('filteredListData')"
+        tooltip="{{ 'YANGMAN_LIST_NEXT_ITEM' | translate }}"
+        class="yangButton iconNext"></button>
diff --git a/modules/yangman-resources/src/main/resources/yangman/views/rightpanel/form/operational/list.tpl.html b/modules/yangman-resources/src/main/resources/yangman/views/rightpanel/form/operational/list.tpl.html
new file mode 100644 (file)
index 0000000..8d9a586
--- /dev/null
@@ -0,0 +1,51 @@
+<div ng-controller="YMListCtrl as yangList"
+     class="yangmanModule__right-panel__form__element-container"
+     ng-class="{'expanded' : node.expanded}"
+     ng-show="node.isFilled()">
+
+    <!-- container title -->
+    <div layout="row"
+         layout-align="start center"
+         class="container-label">
+
+        <!-- Expand Icon -->
+        <md-icon md-font-set="material-icons" class="top-icon top-element pointer" ng-click="yangList.toggleExpanded()">
+            <md-tooltip md-direction="left">{{ 'YANGMAN_SHOW_HIDE_CON' | translate }}</md-tooltip>
+            {{node.expanded ? 'keyboard_arrow_down':'keyboard_arrow_right'}}
+        </md-icon>
+
+        <!-- list label -->
+        <p class="top-element pointer list-label" ng-click="yangList.toggleExpanded()" ym-info-box node="node">
+            {{yangForm.getNodeName(node.localeLabel, node.label)}}
+        </p>
+
+        <!-- Action menu -->
+        <yang-form-menu is-action-menu="yangList.isActionMenu()"
+                        augmentations="augmentations"
+                        yang-form="yangForm"
+                        yang-list="yangList"
+                        node="node"></yang-form-menu>
+
+        <!--<ng-include src="currentPath+'/filter.tpl.html'"></ng-include>-->
+
+        <section layout="row"
+                 layout-align="start center"
+                 class="yangmanModule__right-panel__form__list__paginator"
+                 ng-include="yangForm.viewPath + '/list-data-top.tpl.html'"
+                 ng-if="!(node.filteredListData && node.filteredListData.length)"></section>
+
+        <div class="listItemWrapper"
+             ng-include="yangForm.viewPath + '/config/list-filtered-data-top.tpl.html'"
+             ng-if="(node.filteredListData && node.filteredListData.length)"></div>
+
+    </div>
+
+    <!-- list's children -->
+    <div ng-if="node.actElemStructure" ng-show="node.expanded">
+        <div ng-repeat="node in node.actElemStructure.getChildren(null,null,constants.NODE_UI_DISPLAY)"
+             ng-include="yangForm.viewPath + '/operational/' + node.type+'.tpl.html'"
+             ng-hide="node.augmentationId && !augmentations.getAugmentation(node.parent, node.augmentationId).expanded">
+        </div>
+    </div>
+</div>
+
diff --git a/modules/yangman-resources/src/main/resources/yangman/views/rightpanel/form/operational/output.tpl.html b/modules/yangman-resources/src/main/resources/yangman/views/rightpanel/form/operational/output.tpl.html
new file mode 100644 (file)
index 0000000..a7ff88b
--- /dev/null
@@ -0,0 +1,35 @@
+<div ng-controller="YMOutputCtrl as yangOutput"
+     class="yangmanModule__right-panel__form__element-container"
+     ng-class="{'expanded' : node.expanded}"
+     ng-show="node.isFilled()">
+
+    <!-- container title -->
+    <div layout="row"
+         layout-align="start center"
+         class="pointer container-label"
+         ng-click="yangOutput.toggleExpanded()">
+
+        <!-- Expand Icon -->
+        <md-icon md-font-set="material-icons" class="top-icon top-element">
+            <md-tooltip md-direction="left">{{ 'YANGMAN_SHOW_HIDE_CON' | translate }}</md-tooltip>
+            {{node.expanded ? 'keyboard_arrow_down':'keyboard_arrow_right'}}
+        </md-icon>
+
+        <!-- Container label -->
+        <p class="top-element" ym-info-box node="node"> {{yangForm.getNodeName(node.localeLabel, node.label)}} </p>
+
+        <!-- Action menu -->
+        <yang-form-menu is-action-menu="yangOutput.isActionMenu()"
+                        augmentations="augmentations"
+                        node="node"></yang-form-menu>
+
+    </div>
+
+    <!-- output's children -->
+    <div ng-if="node.expanded">
+        <div ng-repeat="node in node.getChildren(null,null,constants.NODE_UI_DISPLAY)"
+             ng-include="yangForm.viewPath + '/operational/' + node.type+'.tpl.html'"
+             ng-hide="node.augmentationId && !augmentations.getAugmentation(node.parent, node.augmentationId).expanded">
+        </div>
+    </div>
+</div>
diff --git a/modules/yangman-resources/src/main/resources/yangman/views/rightpanel/form/operational/rpc.tpl.html b/modules/yangman-resources/src/main/resources/yangman/views/rightpanel/form/operational/rpc.tpl.html
new file mode 100644 (file)
index 0000000..417eeba
--- /dev/null
@@ -0,0 +1,33 @@
+<div ng-controller="YMRpcCtrl as yangRpc"
+     class="yangmanModule__right-panel__form__element-container"
+     ng-class="{'expanded' : node.expanded}"
+     ng-show="node.isFilled()">
+
+    <!-- container title -->
+    <div layout="row"
+         layout-align="start center"
+         class="pointer container-label"
+         ng-click="yangRpc.toggleExpanded()">
+
+        <!-- Expand Icon -->
+        <md-icon md-font-set="material-icons" class="top-icon top-element">
+            <md-tooltip md-direction="left">{{ 'YANGMAN_SHOW_HIDE_CON' | translate }}</md-tooltip>
+            {{node.expanded ? 'keyboard_arrow_down':'keyboard_arrow_right'}}
+        </md-icon>
+
+        <!-- Container label -->
+        <p class="top-element" ym-info-box node="node"> {{yangForm.getNodeName(node.localeLabel, node.label)}} </p>
+
+        <!-- Action menu -->
+        <yang-form-menu is-action-menu="yangRpc.isActionMenu()"
+                        augmentations="augmentations"
+                        node="node"></yang-form-menu>
+
+    </div>
+
+    <!-- Rpc's children -->
+    <div ng-if="node.expanded">
+        <div ng-repeat="node in node.getChildren(null,null,constants.NODE_UI_DISPLAY)"
+             ng-include="yangForm.viewPath + '/operational/' + node.type + '.tpl.html'"></div>
+    </div>
+</div>
diff --git a/modules/yangman-resources/src/main/resources/yangman/views/rightpanel/form/operations/rpc.tpl.html b/modules/yangman-resources/src/main/resources/yangman/views/rightpanel/form/operations/rpc.tpl.html
new file mode 100644 (file)
index 0000000..30e8c2a
--- /dev/null
@@ -0,0 +1,32 @@
+<div ng-controller="YMRpcCtrl as yangRpc"
+     class="yangmanModule__right-panel__form__element-container"
+     ng-class="{'expanded' : node.expanded}">
+
+    <!-- container title -->
+    <div layout="row"
+         layout-align="start center"
+         class="pointer container-label"
+         ng-click="yangRpc.toggleExpanded()">
+
+        <!-- Expand Icon -->
+        <md-icon md-font-set="material-icons" class="top-icon top-element">
+            <md-tooltip md-direction="left">{{ 'YANGMAN_SHOW_HIDE_CON' | translate }}</md-tooltip>
+            {{node.expanded ? 'keyboard_arrow_down':'keyboard_arrow_right'}}
+        </md-icon>
+
+        <!-- Container label -->
+        <p class="top-element" ym-info-box node="node"> {{yangForm.getNodeName(node.localeLabel, node.label)}} </p>
+
+        <!-- Action menu -->
+        <yang-form-menu is-action-menu="yangRpc.isActionMenu()"
+                        augmentations="augmentations"
+                        node="node"></yang-form-menu>
+
+    </div>
+
+    <!-- Rpc's children -->
+    <div ng-if="node.expanded">
+        <div ng-repeat="node in node.getChildren(null,null,constants.NODE_UI_DISPLAY) | ymOnlyConfigElem"
+             ng-include="yangForm.viewPath + '/config/' + node.type + '.tpl.html'"></div>
+    </div>
+</div>
diff --git a/modules/yangman-resources/src/main/resources/yangman/views/rightpanel/request-data.tpl.html b/modules/yangman-resources/src/main/resources/yangman/views/rightpanel/request-data.tpl.html
new file mode 100644 (file)
index 0000000..79261d9
--- /dev/null
@@ -0,0 +1,11 @@
+<textarea ng-model="requestData.data"
+          ui-codemirror
+          ui-codemirror-opts="requestData.dataEditorOptions"
+          class="codemirror-container">
+</textarea>
+
+<div class="paramsBox" ng-show="requestData.paramsArray.length">
+    <div  ng-repeat="param in requestData.paramsArray" class="line">
+        <strong>&lt;&lt;{{param.name}}&gt;&gt;</strong> : <span>{{param.value !== undefined ? param.value : 'YANGMAN_PARAM_DONT_REPLACE' | translate}}</span>
+    </div>
+</div>
diff --git a/modules/yangman-resources/src/main/resources/yangman/views/rightpanel/request-header.tpl.html b/modules/yangman-resources/src/main/resources/yangman/views/rightpanel/request-header.tpl.html
new file mode 100644 (file)
index 0000000..3857496
--- /dev/null
@@ -0,0 +1,163 @@
+<md-content layout="column" layout-wrap class="md-padding" ng-controller="RequestHeaderCtrl as requestHeader">
+    <section layout="row">
+        <!-- Methods selector -->
+        <md-input-container flex="initial">
+            <md-select ng-model="requestHeader.selectedOperation"
+                       md-on-close="requestHeader.setJsonView()"
+                       placeholder="{{'YANGMAN_SEL_METHOD' | translate}}">
+
+                <md-option ng-value="operation" ng-repeat="operation in requestHeader.selectedOperationsList">
+                    {{ operation }}
+                </md-option>
+            </md-select>
+        </md-input-container>
+
+        <!-- Request url input -->
+        <section flex layout="row" layout-wrap>
+            <md-input-container flex md-no-float ng-if="rightPanelSection === requestHeader.constants.DISPLAY_TYPE_REQ_DATA">
+                <input type="text"
+                       ng-model="requestHeader.requestUrl"
+                       placeholder="{{'YANGMAN_REQ_URL' | translate}}"
+                       spellcheck="false">
+            </md-input-container>
+
+            <div ng-repeat="pathElem in selectedSubApi.pathArray"
+                 flex="nogrow"
+                 layout="row"
+                 ng-if="rightPanelSection === requestHeader.constants.DISPLAY_TYPE_FORM">
+
+                <md-input-container flex="nogrow" md-no-float class="input-span nrp" >
+                    <span class="md-input" disabled>
+                        {{(pathElem.moduleChanged ? '/' + pathElem.module + ':' : '/') + pathElem.name}}
+                        {{pathElem.hasIdentifier() ? '/' : ''}}
+                    </span>
+                </md-input-container>
+
+                <!-- Identifier's inputs -->
+                <md-input-container flex="nogrow" md-no-float
+                                    ng-repeat="identifier in pathElem.identifiers"
+                                    ng-show="pathElem.hasIdentifier()"
+                                    layout="column"
+                                    class="nrp">
+
+                    <input type="text"
+                           class="input-identifier"
+                           ng-change="requestHeader.fillNodeData(pathElem, identifier)"
+                           ng-model="identifier.value"
+                           aria-label="{{identifier.value}}"
+                           ng-class="{'md-has-error': !identifier.value.length}"
+                           spellcheck="false">
+                    <!-- input error message -->
+                    <div ng-show="!identifier.value.length" class="md-custom-error">
+                        {{'YANGMAN_INPUT_REQUIRED' | translate}}
+                    </div>
+                </md-input-container>
+            </div>
+
+            <md-input-container flex md-no-float
+                                ng-if="rightPanelSection === requestHeader.constants.DISPLAY_TYPE_FORM"
+                                class="input-span">
+
+                <input type="text"
+                       placeholder="{{!selectedSubApi ? ('YANGMAN_REQ_URL' | translate) : ''}}"
+                       ng-disabled="true">
+            </md-input-container>
+        </section>
+
+        <!-- Action buttons -->
+        <md-input-container flex="nogrow" layout="row" layout-align="start start" class="action-buttons">
+            <!-- Execute action button -->
+            <md-button class="md-raised md-primary has-progress"
+                       ng-click="requestHeader.prepareDataAndExecute(
+                            main.modulesTreeDisplayed() ? main.leftPanelShowModule : null
+                       )">
+                {{'YANGMAN_SEND' | translate}}
+            </md-button>
+
+            <!-- Save request -->
+            <md-button class="md-raised md-warn" ng-click="requestHeader.saveRequestToCollection($event)">
+                {{'YANGMAN_SAVE' | translate}}
+            </md-button>
+
+            <!-- Parameters button -->
+            <md-button class="md-raised" ng-click="requestHeader.showParamsAdmin($event)">
+                {{'YANGMAN_PARAMETERS' | translate}}
+            </md-button>
+
+            <!-- sub api custom functionality menu -->
+            <md-menu ng-show="selectedSubApi.custFunct.length || requestHeader.selectedPluginsButtons.length">
+                <md-button aria-label="Open demo menu" class="md-icon-button" ng-click="$mdOpenMenu($event)">
+                    <md-icon md-font-set="material-icons">more_vert</md-icon>
+                    <md-tooltip md-direction="top">{{ 'YANGMAN_PLUGINS_MENU' | translate}}</md-tooltip>
+                </md-button>
+
+                <md-menu-content>
+                    <!-- plugins buttons -->
+                    <md-menu-item ng-repeat="pluginFunctionality in selectedSubApi.custFunct"
+                                  ng-hide="requestHeader.selectedPlugin">
+                        <md-button ng-click="requestHeader.executePluginFunctionality(pluginFunctionality)">
+                            {{ pluginFunctionality.label | translate }}
+                        </md-button>
+                    </md-menu-item>
+
+                    <!-- plugin own buttons -->
+                    <md-menu-item ng-repeat="button in requestHeader.selectedPluginsButtons" ng-show="button.show()">
+                        <md-button ng-click="button.onclick()">
+                            {{ button.label | translate }}
+                        </md-button>
+                    </md-menu-item>
+                </md-menu-content>
+            </md-menu>
+        </md-input-container>
+    </section>
+
+    <md-divider flex="grow"></md-divider>
+
+    <section layout="row" layout-align="center center" class="status-bar">
+        <!-- Data type switcher - radio button -->
+        <md-radio-group ng-model="requestHeader.selectedShownDataType"
+                        class="type-switcher"
+                        flex="50"
+                        layout="row"
+                        layout-align="start center"
+                        ng-change="requestHeader.changeDataType()">
+            <md-radio-button value="form" aria-label="{{'YANGMAN_FORM' | translate}}">
+                {{'YANGMAN_FORM' | translate}}
+            </md-radio-button>
+
+            <md-radio-button value="req-data" aria-label="{{'YANGMAN_JSON' | translate}}">
+                {{'YANGMAN_JSON' | translate}}
+            </md-radio-button>
+        </md-radio-group>
+
+        <!-- Request info box -->
+        <md-content flex="50"
+                    layout="row"
+                    layout-align="end center"
+                    class="status-text">
+
+            <!-- Status -->
+            <span flex="30">
+                {{'YANGMAN_STATUS' | translate}}:
+                <span ng-if="requestHeader.statusObj && requestHeader.statusObj.statusText">
+                    {{requestHeader.statusObj.status}} {{requestHeader.statusObj.statusText}}
+                </span>
+                <span ng-if="!(requestHeader.statusObj && requestHeader.statusObj.statusText)">
+                    ...
+                </span>
+            </span>
+
+            <!-- Request time -->
+            <span flex="30">
+                {{'YANGMAN_TIME' | translate}}:
+                <span ng-if="requestHeader.statusObj && requestHeader.statusObj.time">
+                    {{requestHeader.statusObj.time}} ms
+                </span>
+                <span ng-if="!(requestHeader.statusObj && requestHeader.statusObj.time)">
+                    ...
+                </span>
+            </span>
+        </md-content>
+    </section>
+</md-content>
+<md-progress-linear md-mode="indeterminate" ng-show="main.executingRequestProgress"></md-progress-linear>
diff --git a/modules/yangman-resources/src/main/resources/yangman/views/root.tpl.html b/modules/yangman-resources/src/main/resources/yangman/views/root.tpl.html
new file mode 100644 (file)
index 0000000..b57b957
--- /dev/null
@@ -0,0 +1 @@
+<div class="main yangmanModule row" ui-view></div>
diff --git a/modules/yangman-resources/src/main/resources/yangman/yangman.filters.js b/modules/yangman-resources/src/main/resources/yangman/yangman.filters.js
new file mode 100644 (file)
index 0000000..f19e978
--- /dev/null
@@ -0,0 +1,20 @@
+define([], function () {
+    'use strict';
+
+    angular.module('app.yangman').filter('ymOnlyConfigElem', YmOnlyConfigElemFilter);
+
+    YmOnlyConfigElemFilter.$inject = ['NodeUtilsService'];
+
+    function YmOnlyConfigElemFilter(NodeUtilsService){
+        return function (nodes){
+            if (nodes.length) {
+                nodes = nodes.filter(function (n){
+                    return NodeUtilsService.isOnlyOperationalNode(n);
+                });
+            }
+
+            return nodes;
+        };
+    }
+
+});
diff --git a/modules/yangman-resources/src/main/resources/yangman/yangman.less b/modules/yangman-resources/src/main/resources/yangman/yangman.less
new file mode 100644 (file)
index 0000000..66e9e6e
--- /dev/null
@@ -0,0 +1,1295 @@
+// general
+@fontColor : #505050;
+@fontColorLight: #a9a9a9;
+@fontHighlight: orange;
+@listBackColor: #f8f8f8;
+@listActiveColor: #E7E7E7;
+@appBackColor: #ffffff;
+@unactiveTabFontColor: #a9a9a9;
+@colorActive: rgb(64,196,255);
+@popupHeaderColor: #ffffff;
+
+// yangman
+@leftPanelBackColor: #f3f3f3;
+@infoBoxBackColor: rgba(255, 255, 255, 0.25);
+@infoBoxBorderColor: #aad1f9;
+@dataStoreListHoverColor: #dadada;
+@dataStoreListShadowColor: rgba(0,0,0,.14);
+@dataStoreListBorderColor: rgba(0,0,0,0.12);
+@dashedBorderColor: rgba(0,0,0,0.54);
+@inputColor: rgba(0,0,0,0.87);
+@reqMethodGet: #63d33b;
+@reqMethodPut: #6fbad3;
+@reqMethodPost: #ea9c30;
+@reqMethodDelete: #eabb2f;
+@reqError: #ff0000;
+@darkBlueColor: rgb(33,150,243);
+
+// helpers
+.pointer{
+    cursor: pointer;
+    outline: 0 none;
+}
+
+.no-wrap{
+    white-space: nowrap;
+}
+
+.text-center{
+    text-align: center;
+}
+
+.text-left{
+    text-align: left;
+}
+
+.h100{
+    height: 100%;
+}
+
+.mb30{
+    margin-bottom: 30px;
+}
+
+.mr8{
+    margin-right: 8px;
+}
+
+.nrp{
+    padding-right: 0!important;
+}
+
+.flex-center {
+    align-items: center;
+    justify-content: center;
+}
+
+// general
+.md-open-menu-container{
+    span{
+        color: @fontColor;
+    }
+
+    h5{
+        margin: 0 16px;
+        color: @unactiveTabFontColor;
+
+        md-icon{
+            color: @unactiveTabFontColor;
+            font-size: 18px;
+        }
+    }
+
+    md-menu-content{
+        .info-box{
+            position: absolute;
+            left: 100%;
+            top: 0;
+            margin-left: 10px;
+            min-width: 300px;
+            padding: 0;
+            z-index: 10;
+            background: #fff;
+            -webkit-transition: all 150ms linear;
+            -moz-transition: all 150ms linear;
+            -ms-transition: all 150ms linear;
+            -o-transition: all 150ms linear;
+            transition: all 150ms linear;
+            opacity: 1;
+            max-height: 300px;
+            overflow-y: auto;
+            overflow-x: hidden;
+
+            &__padding{
+                padding: 16px;
+            }
+
+            &.ng-hide{
+                opacity: 0;
+            }
+        }
+    }
+
+    svg {
+         border: none;
+         border-radius: 0px;
+         background-image: none;
+    }
+
+    .icon-wrapper{
+        padding: 0 16px;
+    }
+}
+
+.md-select-menu-container{
+    z-index: 1000;
+}
+
+.svg-icon{
+    width: 24px;
+    height: 24px;
+    padding-top: 4px;
+    padding-bottom: 4px;
+    color: @dashedBorderColor;
+}
+
+md-ink-bar.custom{
+    width: 100%;
+    color: @colorActive;
+    left: 0;
+    background: @colorActive;
+}
+
+button{
+    label{
+        font-weight: normal;
+    }
+}
+
+.ui-resizable-e{
+    cursor: e-resize;
+    height: 100%;
+    width: 7px;
+    top: 0;
+    position: absolute;
+    right: 0;
+}
+
+md-dialog{
+    md-autocomplete{
+        height: 50px !important;
+    }
+}
+
+.info-box-container{
+    position: relative;
+
+    &__hover-wrapper{
+        display: inline-block;
+        width: 100%;
+    }
+
+    .info-box{
+        position: absolute;
+        left: 90%;
+        top: 0;
+        margin-left: 10px;
+        margin-bottom: 10px;
+        min-width: 300px;
+        padding: 0;
+        z-index: 10;
+        background: #fff;
+        -webkit-transition: all 150ms linear;
+        -moz-transition: all 150ms linear;
+        -ms-transition: all 150ms linear;
+        -o-transition: all 150ms linear;
+        transition: all 150ms linear;
+        opacity: 1;
+        max-height: 300px;
+        overflow-y: auto;
+        overflow-x: hidden;
+
+        &__padding{
+            padding: 16px;
+        }
+
+        &.ng-hide{
+            opacity: 0;
+        }
+
+        span{
+            color: @fontColor;
+        }
+    }
+
+    md-menu-divider{
+        margin-top: 4px;
+        margin-bottom: 4px;
+        height: 1px;
+        min-height: 1px;
+        max-height: 1px;
+        width: 100%;
+        background-color: @dataStoreListBorderColor;
+        display: block;
+    }
+}
+
+md-input-container{
+    position: relative;
+
+    input.md-has-error{
+        border-color: @reqError!important;
+    }
+
+    .md-custom-error{
+        color: @reqError;
+        margin-top: 4px;
+        margin-left: 3px;
+        font-size: 11px;
+        line-height: 14px;
+        -webkit-order: 3;
+        -ms-flex-order: 3;
+        order: 3;
+    }
+}
+
+.md-dialog-container{
+    z-index: 99;
+}
+
+// yangman
+.yangmanModule{
+    background-color: @appBackColor;
+    color: @fontColor;
+    height: 100%;
+
+    .ui-resizable-s{
+        height: 13px;
+    }
+
+    .box-container{
+        padding: 16px;
+        margin: 8px 0;
+    }
+
+    .historyTab{
+        height: calc(~'100% - 62px');
+    }
+
+    .collectionsTab{
+        height: calc(~'100% - 62px');
+    }
+
+
+    p{
+        margin: 0;
+    }
+
+    h1, h2, h3, h4, h5, h6{
+        color: @fontColor;
+    }
+
+    .scrollableY{
+        overflow-y: auto;
+        height: 100%;
+    }
+
+    .scrollableX{
+        overflow-x: auto;
+        //width: 100%;
+    }
+
+    .highlight{
+        color: @darkBlueColor;
+    }
+    md-tabs-content-wrapper{
+        top: 0!important;
+    }
+
+    // modules switcher -> list && detail
+    .arrow-switcher{
+        position: absolute;
+        top: 2px;
+        cursor: pointer;
+        outline: 0 none;
+        z-index: 10;
+        font-size: 2.5em;
+        left: -11px;
+        -webkit-transition: all 250ms ease-out;
+        -moz-transition: all 250ms ease-out;
+        -ms-transition: all 250ms ease-out;
+        -o-transition: all 250ms ease-out;
+        transition: all 250ms ease-out;
+
+        &__left{
+            //right: -11px;
+            left: calc(~'100% - 24px');
+            -moz-transform: rotate(180deg);
+            -webkit-transform: rotate(180deg);
+            -o-transform: rotate(180deg);
+            -ms-transform: rotate(180deg);
+            transform: rotate(180deg);
+        }
+
+        &.ng-hide{
+            opacity: 0;
+        }
+    }
+
+    md-dialog{
+        h2{
+            color: @popupHeaderColor;
+        }
+
+        &-actions{
+            button{
+                span{
+                    color: @fontColor;
+                }
+            }
+        }
+
+
+    }
+    // left panel
+    &__left-panel{
+        overflow-x: hidden;
+        background: @leftPanelBackColor;
+        position: relative;
+
+        &__search{
+            padding: 10px 13px;
+            background: @listBackColor;
+            min-height: 62px;
+
+            .md-errors-spacer{
+                display: none;
+            }
+
+            md-icon{
+                color: @dashedBorderColor;
+            }
+
+            .collection-button-container {
+                margin-top: 6px;
+            }
+
+            button {
+                margin: 0;
+                min-width: 35px;
+            }
+
+            md-menu button {
+                margin-top: 6px;
+            }
+
+
+
+
+
+            .md-has-icon.modules-list-search{
+                padding: 2px 25px;
+                margin: 0;
+
+                .md-input{
+                    width: auto;
+                    order: 0;
+                }
+
+                button{
+                    margin: 0;
+                    padding: 0;
+                    min-width: 0;
+                    min-height: 0;
+                    line-height: normal;
+
+                    &:hover, &:focus, &:active, &:visited{
+                        background: transparent;
+                    }
+
+                    .md-ripple-container{
+                        display: none;
+                    }
+                }
+            }
+        }
+
+        md-tabs,
+        md-tab-content > div,
+        md-content,
+        .h100{
+            height: 100%;
+        }
+
+        md-tabs-canvas{
+            border-bottom: 1px solid #dbdbdb;
+            padding-top: 30px;
+            height: 78px;
+        }
+
+        md-ink-bar{
+            height: 4px;
+        }
+
+        md-content{
+            background: transparent;
+        }
+
+        .md-tab{
+            span{
+                color: @unactiveTabFontColor;
+            }
+
+            &.md-active{
+                span{
+                    color: @fontColor;
+                }
+            }
+        }
+
+        &__detail-list-tabs-container{
+            > md-tabs-wrapper{
+                display: none;
+            }
+
+            .inline-tabs > md-tabs-wrapper{
+                display: inline;
+            }
+        }
+
+        .searchBox{
+            height: auto;
+            padding: 10px 13px;
+            font-size: 14px;
+
+            #importCollection{
+                display: none;
+            }
+
+            label{
+                margin-bottom: 0;
+            }
+
+            md-icon.clickable{
+                cursor: pointer;
+            }
+
+            #importParameters{
+                display: none;
+            }
+
+            > button{
+                margin: 6px 0 0 0;
+                height: 30px;
+                min-width: 35px;
+                padding: 0;
+            }
+
+            md-menu{
+                margin: 0;
+                height: 30px;
+                min-width: 35px;
+                padding: 0;
+
+                > button{
+                    min-width: 35px;
+                }
+            }
+
+
+        }
+
+        //loading panel
+        &__loading-container {
+            display: block;
+            position: relative;
+            border: 2px solid @infoBoxBorderColor;
+            transition: opacity  0.1s linear;
+            border-top: 0px;
+            margin: 10px;
+
+            .bottom-block {
+                display: block;
+                position: relative;
+                background-color: @infoBoxBackColor;
+                height: 85px;
+
+                > span {
+                    display: inline-block;
+                    margin-top: 10px;
+                    padding: 25px;
+                    font-size: 0.9em;
+                }
+            }
+        }
+    }
+
+    // right panel
+    &__right-panel{
+        height: 100%;
+
+        .bottom-content{
+            height: calc(~'100% - 195px');
+            overflow-y: auto;
+            margin-top: 25px;
+
+            .codemirror-container{
+                height: 100%;
+            }
+        }
+
+        &__header{
+            margin-bottom: 30px;
+
+            > md-content{
+                background: @leftPanelBackColor;
+
+                md-content{
+                    background: transparent;
+                }
+            }
+
+            md-progress-linear{
+                margin-top: -5px;
+            }
+
+            md-input-container{
+                margin: 0;
+            }
+
+            .md-errors-spacer{
+                display: none;
+            }
+
+            .input-span{
+                padding-top: 3px;
+            }
+
+            .input-identifier{
+                max-width: 80px;
+                border-color: @colorActive;
+                padding-left: 0;
+            }
+
+            md-divider{
+                margin-top: 20px;
+            }
+
+            .status-bar{
+                min-height: 60px;
+
+                .status-text{
+                    span span{
+                        color: @colorActive;
+                    }
+                }
+            }
+        }
+
+        &__req-data{
+
+            &__header{
+
+                h5{
+                    padding-top: 10px;
+                }
+
+                button{
+                    margin: 0;
+                    margin-bottom: 2px;
+                    min-width: 0!important;
+                    width: 46px;
+
+                    .material-icons{
+                        margin-bottom: 6px;
+                        vertical-align: bottom;
+                    }
+
+                    .bigger{
+                        font-size: 25px;
+                    }
+
+                    .smaller{
+                        font-size: 18px;
+                    }
+
+                    .additional{
+                        margin-left: -15px;
+                        vertical-align: top;
+                    }
+                }
+
+            }
+
+            > div{
+                height: 100%;
+                padding-right: 2px;
+                padding-bottom: 10px;
+                position: relative;
+
+
+                > div:not(.ui-resizable-handle) {
+                    height: calc(~'100% - 28px');
+                    overflow-y: auto;
+                }
+
+                h5{
+                    margin-top: 0;
+                }
+
+                &.half-size{
+                    height: 50%;
+                }
+            }
+
+            .paramsBox{
+                position: absolute;
+                top: 50px;
+                right: 26px;
+                background-color: rgba(235, 235, 228, 0.62);
+                padding: 15px;
+            }
+
+            .CodeMirror { height: 100%; }
+
+            md-toast{
+                margin-top: 24px;
+            }
+        }
+
+        &__form{
+
+            .box-container.union{
+                padding: 0;
+            }
+
+            .union-tabs{
+                margin: 8px 0;
+
+                md-content{
+                    min-width: 250px;
+                }
+
+                .md-tab{
+                    padding: 6px 12px;
+                }
+
+                md-pagination-wrapper,
+                md-tabs-canvas{
+                    height: 36px;
+                }
+            }
+
+            md-input-container{
+                margin: 0;
+
+                > md-icon {
+                    left: auto;
+                    right: 2px;
+                    color: @dashedBorderColor;
+                }
+
+                &.md-has-icon{
+                    padding-right: 36px;
+                    padding-left: 0px;
+                }
+
+                .md-errors-spacer{
+                    display: none;
+                }
+            }
+
+            .md-menu.menu-container{
+                position: relative;
+                padding: 0;
+
+
+
+                .md-button{
+                    margin: auto 0;
+                    text-transform: none;
+                    text-align: start;
+                    height: 100%;
+                    padding-left: 16px;
+                    padding-right: 16px;
+                    display: inline-block;
+                    width: 100%;
+
+                    &.md-icon-button{
+                        padding: 0 8px;
+                    }
+
+                }
+
+                .yang-menu-content{
+                    box-shadow: 1px 1px 10px #888;
+                    position: absolute;
+                    left: 0;
+                    z-index: 100;
+                    background: #fff;
+                    padding: 8px 0;
+
+                    md-divider{
+                        padding: 4px 0 4px 0;
+                    }
+
+                    .title{
+                        color: #a9a9a9;
+                        margin: 0 16px;
+
+                        md-icon{
+                            font-size: 18px;
+                        }
+                    }
+
+                    .yang-menu-item{
+                        min-height: 48px;
+                        height: 48px;
+
+                        md-icon{
+                            margin: auto 16px auto 0;
+                        }
+                    }
+
+                }
+
+                .info-box{
+                    position: absolute;
+                    left: 100%;
+                    top: 0;
+                    margin-left: 10px;
+                    min-width: 300px;
+                    padding: 0;
+                    z-index: 10;
+                    background: #fff;
+                    transition: all 150ms linear;
+                    opacity: 1;
+                    max-height: 300px;
+                    overflow-y: auto;
+                    overflow-x: hidden;
+
+                    &__padding{
+                        padding: 16px;
+                    }
+
+                    &.ng-hide{
+                        opacity: 0;
+                    }
+                }
+
+            }
+
+            .menu-placeholder{
+                padding: 11px 26px;
+            }
+
+            p.top-element{
+                margin: 5px 10px 0 0;
+                word-wrap: break-word;
+                width: 100px;
+
+                &.list-label{
+                    color: @colorActive;
+                }
+            }
+
+            &__element-container{
+                margin: 25px 5px 5px 15px;
+                padding: 5px;
+
+                &.expanded{
+                    border-left: 1px dashed @dashedBorderColor;
+                }
+
+                md-input-container{
+                    &.input-icon-container{
+                        margin-left: 15px;
+
+                        md-icon{
+                            margin: 0;
+                        }
+                    }
+                }
+
+                .container-label{
+                    margin: -20px 0 10px -17px;
+
+                    md-icon{
+                        margin: 0;
+                    }
+                }
+            }
+
+            &__leaf-container{
+                padding-left: 10px;
+
+                md-input-container,
+                md-switch,
+                md-checkbox{
+                    margin: 5px 0;
+                }
+            }
+
+            &__list{
+                &__paginator{
+                    //margin-left: 40px;
+                    button {
+                        background: transparent;
+                        border: 0;
+                        outline: 0 none;
+                    }
+                }
+            }
+
+            &__list-item{
+                margin: 0 5px;
+
+                md-tab-item{
+                    position: relative;
+
+                    &.md-tab{
+                        padding: 6px 12px;
+                    }
+                }
+            }
+        }
+    }
+
+
+    //modules list
+    &__modules-list{
+        padding: 0;
+        background: @listBackColor;
+        height: calc(~"100% - 62px")!important;
+
+        h4{
+            margin: 0;
+            padding: 10px 20px;
+        }
+
+        &__item{
+            padding: 0!important;
+
+            .title{
+                -webkit-transition: all 150ms ease;
+                -moz-transition: all 150ms ease;
+                -ms-transition: all 150ms ease;
+                -o-transition: all 150ms ease;
+                transition: all 150ms ease;
+            }
+
+            &.expanded{
+                background: @listActiveColor;
+            }
+
+            &.selected{
+                .title{
+                    background-color: @colorActive!important;
+                    color: #fff!important;
+                }
+            }
+
+            p.top-element{
+                padding: 6px 0;
+            }
+
+            md-icon{
+                margin: 12px 16px;
+
+                &.top-element{
+                    margin: 0;
+                    padding: 12px 16px;
+                    width: 56px;
+                    height: 48px;
+                }
+            }
+
+            &:hover{
+                .title{
+                    background: @listActiveColor;
+                }
+            }
+        }
+    }
+
+    // datastore list
+    &__datastore-list{
+        padding: 0;
+        border-top: 1px solid @dataStoreListBorderColor;
+        background: @listBackColor;
+        -webkit-box-shadow:inset 0 7px 7px -5px @dataStoreListShadowColor;
+        box-shadow:inset 0 7px 7px -5px @dataStoreListShadowColor;
+
+        md-list-item {
+            min-height: 0;
+            padding: 0;
+            font-size: .85em;
+
+            &:hover{
+                background: @dataStoreListHoverColor;
+            }
+
+            md-icon{
+                margin: 6px 16px 6px 48px;
+                font-size: 20.4px;
+            }
+        }
+    }
+
+    // module history collections tabs
+    &__mhc-tabs{
+
+        md-list-item{
+            .md-no-style{
+                padding: 0;
+            }
+        }
+
+        > md-tabs-content-wrapper{
+            height: calc(~'100% - 78px');
+
+            > md-tab-content{
+                height: 100%;
+            }
+        }
+    }
+
+    // module detail
+    &__module-detail{
+        h4{
+            padding-top: 30px;
+            margin: 0 15px;
+        }
+
+        .tabs{
+            height: calc(~'100% - 49px');
+
+            md-tabs-canvas{
+                padding-top: 0;
+                height: 48px;
+            }
+
+            > md-tabs-content-wrapper{
+                height: calc(~'100% - 48px');
+
+                > md-tab-content{
+                    height: 100%;
+                }
+            }
+
+            .md-tab{
+                padding: 0;
+            }
+
+            md-tab-item{
+                span{
+                    outline: 0 none;
+                    padding: 12px 24px;
+                }
+            }
+        }
+
+        > div{
+            height: 100%;
+
+            > md-content{
+                overflow-y: hidden;
+            }
+        }
+    }
+
+    &__requests-list{
+        background: @listBackColor;
+        padding: 0;
+
+        .md-subheader{
+            background: none;
+
+        }
+
+        md-list{
+            padding-top: 0;
+        }
+
+        &__item-container{
+            position: relative;
+        }
+
+        &__group{
+
+            padding: 0!important;
+
+            &__item{
+
+                &.selected{
+                    background-color: @colorActive;
+
+                    .yangmanModule__requests-list__group__item__path{
+                        color: #fff;
+                    }
+
+                    .yangmanModule__requests-list__group__item__method{
+                        .GET, .PUT, .POST, .DELETE, .error{
+                            color: #fff;
+                        }
+                    }
+                }
+
+                &__path{
+                    white-space: -webkit-pre-wrap; /*Chrome & Safari */
+                    word-break: break-all;
+                    white-space: normal;
+                    line-height: 18px;
+                    color: @fontColor;
+                    padding: 5px 0;
+
+                    p{
+                        padding: 0 9px;
+                    }
+                }
+
+                &__method{
+
+                    padding-left: 17px;
+                    min-width: 70px;
+
+                    .GET{
+                        color: @reqMethodGet;
+                    }
+                    .PUT{
+                        color: @reqMethodPut;
+                    }
+                    .POST{
+                        color: @reqMethodPost;
+                    }
+                    .DELETE{
+                        color: @reqMethodDelete;
+                    }
+                    .error{
+                        color: @reqError;
+                    }
+                }
+            }
+
+            &__itemMenu{
+                position: absolute;
+                top: 50%;
+                margin: -20px 0 0 0;
+                right: 5px;
+                padding: 0;
+
+                &.selected{
+                    > button{
+                        i.material-icons{
+                            color: #fff;
+                        }
+                    }
+                }
+
+                > button{
+                    min-width: 0;
+                    margin: 2px 5px;
+
+                    i.material-icons{
+                        vertical-align: middle;
+                        color: @fontColorLight;
+
+                    }
+                }
+
+            }
+
+            &__collectionMenu{
+                position: relative;
+                margin-left: -52px;
+                margin-right: 6px;
+
+                > button{
+                    min-width: 0;
+                    margin: 2px 5px;
+
+                    i.material-icons{
+                        vertical-align: middle;
+                        color: @fontColorLight;
+                    }
+                }
+
+            }
+        }
+
+        &__collections-list{
+            padding: 0;
+            background: @listBackColor;
+            height: 100%;
+        }
+
+        &__collection{
+            padding: 0;
+            background: @listBackColor;
+
+            &__requests{
+                padding: 0;
+                border-top: 1px solid @dataStoreListBorderColor;
+                background: @listBackColor;
+                -webkit-box-shadow:inset 0 7px 7px -5px @dataStoreListShadowColor;
+                box-shadow:inset 0 7px 7px -5px @dataStoreListShadowColor;
+            }
+
+            .md-subheader{
+                background: none;
+            }
+
+            .md-subheader-inner{
+                padding: 0;
+            }
+
+            .material-icons{
+                margin: 15px 25px;
+            }
+
+            &.expanded{
+                background: @listActiveColor;
+            }
+
+            p{
+                line-height: 18px;
+                padding: 12px 0;
+
+                .desc{
+                    color: @fontColorLight;
+                }
+            }
+
+        }
+
+    }
+}
+.reqMenu{
+    button{
+        span{
+            color: @fontColor
+
+        }
+        i.material-icons{
+            vertical-align: middle;
+            margin-right: 5px;
+            margin-bottom: 5px;
+        }
+    }
+}
+
+
+.md-autocomplete-suggestions{
+    span{
+        color: @fontColor;
+    }
+}
+
+md-dialog{
+
+    .md-toolbar-tools{
+        button{
+            min-width: auto;
+        }
+    }
+
+    md-dialog-content, md-dialog-actions{
+        h2, span{
+            color: @fontColor;
+        }
+
+    }
+
+}
+
+// directives
+.directive{
+    &__abn-tree{
+        padding: 0;
+        display:inline-block;
+        white-space: nowrap;
+        min-width: 100%;
+
+        md-icon{
+            margin: 6px 16px!important;
+        }
+
+        md-list-item{
+            min-height: 0;
+
+            &.active{
+                background: @listActiveColor;
+            }
+
+            .md-no-style{
+                padding: 0;
+
+                &.md-button{
+                    white-space: nowrap;
+                }
+            }
+
+            .md-list-item-inner{
+                min-height: 0;
+            }
+
+            .empty-box{
+                display: inline-block;
+                margin-top: -10px;
+                margin-left: 27px;
+                border-left: 1px dashed @dashedBorderColor;
+                height: 36px;
+                width: 1px;
+            }
+
+            .md-button{
+                overflow: visible;
+            }
+
+            .tree-label{
+                padding-right: 15px;
+            }
+        }
+    }
+}
+
+.paramsAdminDialog{
+
+    .md-dialog-content{
+
+        height: 400px;
+
+        button{
+            height: 30px;
+            min-width: 30px;
+            margin-top: 15px;
+            i{
+                vertical-align: middle;
+            }
+        }
+
+
+    }
+    &__searchBox{
+
+        height: 80px;
+
+        > button{
+            margin-top: 13px!important;
+            margin-right: 0px!important;
+        }
+
+        #importParameters{
+            display: none;
+        }
+
+        label{
+            md-icon{
+                color: @fontColor;
+            }
+        }
+
+        md-menu{
+            button{
+                margin-top: 5px!important;
+            }
+        }
+
+        input{
+            border: none;
+            height: auto;
+            outline: none;
+        }
+    }
+    &__paramsList{
+        width: 450px;
+        padding-top: 35px;
+
+        > div{
+            min-height: 60px;
+            margin-top: 10px;
+        }
+
+
+    }
+}
diff --git a/modules/yangman-resources/src/main/resources/yangman/yangman.module.js b/modules/yangman-resources/src/main/resources/yangman/yangman.module.js
new file mode 100644 (file)
index 0000000..b250196
--- /dev/null
@@ -0,0 +1,75 @@
+define([
+    'angular',
+    'app/routingConfig',
+    'Restangular',
+    'angular-translate',
+    'angular-translate-loader-partial',
+    'ngMaterial',
+    'ngMessages',
+    'common/yangutils/yangutils.module',
+    'codemirror',
+    'codeMirror-showHint',
+    'codeMirror-jsonParametersHint',
+    'codeMirror-javascriptMode',
+    'codeMirror-matchBrackets',
+], function () {
+    'use strict';
+
+    angular.module('app.yangman', [
+        'ui.router.state',
+        'app.core',
+        'app.common.yangUtils',
+        'restangular',
+        'pascalprecht.translate',
+        'ngMaterial',
+        'ngMessages',
+    ]);
+
+    angular.module('app.yangman')
+        .config(YangManConfig)
+        .constant('ymUiCodemirrorConfig', {});
+
+    function YangManConfig($stateProvider, $mdThemingProvider, $translatePartialLoaderProvider,  NavHelperProvider) {
+
+        $translatePartialLoaderProvider.addPart('app/yangman/assets/data/locale');
+
+        $mdThemingProvider.theme('default')
+            .primaryPalette('blue')
+            .accentPalette('light-blue');
+
+        NavHelperProvider.addControllerUrl('app/yangman/controllers/yangman.controller');
+        NavHelperProvider.addToMenu('yangman', {
+            link: '#/yangman/index',
+            active: 'main.yangman',
+            title: 'Yangman',
+            icon: 'icon-rocket',
+            page: {
+                title: 'Yangman',
+                description: 'Yangman',
+            },
+        });
+
+        var access = routingConfig.accessLevels;
+        $stateProvider.state('main.yangman', {
+            url: 'yangman',
+            abstract: true,
+            views: {
+                content: {
+                    templateUrl: 'src/app/yangman/views/root.tpl.html',
+                },
+            },
+        });
+
+        $stateProvider.state('main.yangman.index', {
+            url: '/index',
+            access: access.admin,
+            views: {
+                '': {
+                    controller: 'YangmanCtrl',
+                    controllerAs: 'main',
+                    templateUrl: 'src/app/yangman/views/index.tpl.html',
+                },
+            },
+        });
+    }
+});
index 1244c64f9b36d3285ddb386b604c2aa101a3995e..c077d3d51594df4bcbbaeccc6c880c7179c53acf 100644 (file)
@@ -12,7 +12,7 @@
   <parent>
     <groupId>org.opendaylight.dlux</groupId>
     <artifactId>dlux-parent</artifactId>
-    <version>0.4.0-SNAPSHOT</version>
+    <version>0.5.0-SNAPSHOT</version>
     <relativePath>../../</relativePath>
   </parent>
 
diff --git a/modules/yangui-resources/src/main/resources/yangui/assets/js/codemirror/AUTHORS b/modules/yangui-resources/src/main/resources/yangui/assets/js/codemirror/AUTHORS
deleted file mode 100644 (file)
index 3299d4f..0000000
+++ /dev/null
@@ -1,466 +0,0 @@
-List of CodeMirror contributors. Updated before every release.
-
-4r2r
-Aaron Brooks
-Abdelouahab
-Abe Fettig
-Adam Ahmed
-Adam King
-adanlobato
-Adán Lobato
-Adrian Aichner
-aeroson
-Ahmad Amireh
-Ahmad M. Zawawi
-ahoward
-Akeksandr Motsjonov
-Alberto González Palomo
-Alberto Pose
-Albert Xing
-Alexander Pavlov
-Alexander Schepanovski
-Alexander Shvets
-Alexander Solovyov
-Alexandre Bique
-alexey-k
-Alex Piggott
-Aliaksei Chapyzhenka
-Amin Shali
-Amsul
-amuntean
-Amy
-Ananya Sen
-anaran
-AndersMad
-Anders Nawroth
-Anderson Mesquita
-Andrea G
-Andreas Reischuck
-Andre von Houck
-Andrey Fedorov
-Andrey Klyuchnikov
-Andrey Lushnikov
-Andy Joslin
-Andy Kimball
-Andy Li
-Angelo
-angelozerr
-angelo.zerr@gmail.com
-Ankit
-Ankit Ahuja
-Ansel Santosa
-Anthony Dugois
-Anthony Grimes
-Anton Kovalyov
-AQNOUCH Mohammed
-areos
-as3boyan
-AtomicPages LLC
-Atul Bhouraskar
-Aurelian Oancea
-Bastian Müller
-Bem Jones-Bey
-benbro
-Beni Cherniavsky-Paskin
-Benjamin DeCoste
-Ben Keen
-Bernhard Sirlinger
-Bert Chang
-Billy Moon
-binny
-B Krishna Chaitanya
-Blaine G
-blukat29
-boomyjee
-borawjm
-Brad Metcalf
-Brandon Frohs
-Brandon Wamboldt
-Brett Zamir
-Brian Grinstead
-Brian Sletten
-Bruce Mitchener
-Calin Barbat
-Chandra Sekhar Pydi
-Charles Skelton
-Cheah Chu Yeow
-Chris Coyier
-Chris Granger
-Chris Houseknecht
-Chris Lohfink
-Chris Morgan
-Christian Oyarzun
-Christian Petrov
-Christopher Brown
-Christopher Mitchell
-Christopher Pfohl
-ciaranj
-CodeAnimal
-coderaiser
-ComFreek
-Curtis Gagliardi
-dagsta
-daines
-Dale Jung
-Dan Bentley
-Dan Heberden
-Daniel, Dao Quang Minh
-Daniele Di Sarli
-Daniel Faust
-Daniel Huigens
-Daniel KJ
-Daniel Neel
-Daniel Parnell
-Danny Yoo
-darealshinji
-Darius Roberts
-Dave Myers
-David Barnett
-David Mignot
-David Pathakjee
-David Vázquez
-deebugger
-Deep Thought
-Devon Carew
-dignifiedquire
-Dimage Sapelkin
-Dmitry Kiselyov
-domagoj412
-Dominator008
-Domizio Demichelis
-Doug Wikle
-Drew Bratcher
-Drew Hintz
-Drew Khoury
-Dror BG
-duralog
-eborden
-edsharp
-ekhaled
-Enam Mijbah Noor
-Eric Allam
-eustas
-Fabien O'Carroll
-Fabio Zendhi Nagao
-Faiza Alsaied
-Fauntleroy
-fbuchinger
-feizhang365
-Felipe Lalanne
-Felix Raab
-Filip Noetzel
-flack
-ForbesLindesay
-Forbes Lindesay
-Ford_Lawnmower
-Forrest Oliphant
-Frank Wiegand
-Gabriel Gheorghian
-Gabriel Horner
-Gabriel Nahmias
-galambalazs
-Gautam Mehta
-gekkoe
-Gerard Braad
-Gergely Hegykozi
-Giovanni Calò
-Glenn Jorde
-Glenn Ruehle
-Golevka
-Gordon Smith
-Grant Skinner
-greengiant
-Gregory Koberger
-Guillaume Massé
-Guillaume Massé
-Gustavo Rodrigues
-Hakan Tunc
-Hans Engel
-Hardest
-Hasan Karahan
-Hector Oswaldo Caballero
-Herculano Campos
-Hiroyuki Makino
-hitsthings
-Hocdoc
-Ian Beck
-Ian Dickinson
-Ian Wehrman
-Ian Wetherbee
-Ice White
-ICHIKAWA, Yuji
-ilvalle
-Ingo Richter
-Irakli Gozalishvili
-Ivan Kurnosov
-Ivoah
-Jacob Lee
-Jakob Miland
-Jakub Vrana
-Jakub Vrána
-James Campos
-James Thorne
-Jamie Hill
-Jan Jongboom
-jankeromnes
-Jan Keromnes
-Jan Odvarko
-Jan T. Sott
-Jared Forsyth
-Jason
-Jason Barnabe
-Jason Grout
-Jason Johnston
-Jason San Jose
-Jason Siefken
-Jaydeep Solanki
-Jean Boussier
-jeffkenton
-Jeff Pickhardt
-jem (graphite)
-Jeremy Parmenter
-Jochen Berger
-Johan Ask
-John Connor
-John Lees-Miller
-John Snelson
-John Van Der Loo
-Jonas Döbertin
-Jonathan Malmaud
-jongalloway
-Jon Malmaud
-Jon Sangster
-Joost-Wim Boekesteijn
-Joseph Pecoraro
-Joshua Newman
-Josh Watzman
-jots
-jsoojeon
-ju1ius
-Juan Benavides Romero
-Jucovschi Constantin
-Juho Vuori
-Justin Hileman
-jwallers@gmail.com
-kaniga
-Ken Newman
-Ken Rockot
-Kevin Earls
-Kevin Sawicki
-Kevin Ushey
-Klaus Silveira
-Koh Zi Han, Cliff
-komakino
-Konstantin Lopuhin
-koops
-ks-ifware
-kubelsmieci
-KwanEsq
-Lanfei
-Lanny
-Laszlo Vidacs
-leaf corcoran
-Leonid Khachaturov
-Leon Sorokin
-Leonya Khachaturov
-Liam Newman
-Libo Cannici
-LloydMilligan
-LM
-lochel
-Lorenzo Stoakes
-Luciano Longo
-Luke Stagner
-lynschinzer
-Madhura Jayaratne
-Maksim Lin
-Maksym Taran
-Malay Majithia
-Manuel Rego Casasnovas
-Marat Dreizin
-Marcel Gerber
-Marco Aurélio
-Marco Munizaga
-Marcus Bointon
-Marek Rudnicki
-Marijn Haverbeke
-Mário Gonçalves
-Mario Pietsch
-Mark Lentczner
-Marko Bonaci
-Martin Balek
-Martín Gaitán
-Martin Hasoň
-Martin Hunt
-Mason Malone
-Mateusz Paprocki
-Mathias Bynens
-mats cronqvist
-Matthew Beale
-Matthew Rathbone
-Matthias Bussonnier
-Matthias BUSSONNIER
-Matt McDonald
-Matt Pass
-Matt Sacks
-mauricio
-Maximilian Hils
-Maxim Kraev
-Max Kirsch
-Max Xiantu
-mbarkhau
-Metatheos
-Micah Dubinko
-Michael Grey
-Michael Kaminsky
-Michael Lehenbauer
-Michael Zhou
-Michal Dorner
-Mighty Guava
-Miguel Castillo
-mihailik
-Mike
-Mike Brevoort
-Mike Diaz
-Mike Ivanov
-Mike Kadin
-MinRK
-Miraculix87
-misfo
-mloginov
-Moritz Schwörer
-mps
-ms
-mtaran-google
-Narciso Jaramillo
-Nathan Williams
-ndr
-nerbert
-nextrevision
-ngn
-nguillaumin
-Ng Zhi An
-Nicholas Bollweg
-Nicholas Bollweg (Nick)
-Nick Kreeger
-Nick Small
-Niels van Groningen
-nightwing
-Nikita Beloglazov
-Nikita Vasilyev
-Nikolay Kostov
-nilp0inter
-Nisarg Jhaveri
-nlwillia
-noragrossman
-Norman Rzepka
-pablo
-Page
-Panupong Pasupat
-paris
-Paris
-Patil Arpith
-Patrick Stoica
-Patrick Strawderman
-Paul Garvin
-Paul Ivanov
-Pavel Feldman
-Pavel Strashkin
-Paweł Bartkiewicz
-peteguhl
-Peter Flynn
-peterkroon
-Peter Kroon
-prasanthj
-Prasanth J
-Radek Piórkowski
-Rahul
-Randall Mason
-Randy Burden
-Randy Edmunds
-Rasmus Erik Voel Jensen
-ray ratchup
-Ray Ratchup
-Richard van der Meer
-Richard Z.H. Wang
-Robert Crossfield
-Roberto Abdelkader Martínez Pérez
-robertop23
-Robert Plummer
-Ruslan Osmanov
-Ryan Prior
-sabaca
-Samuel Ainsworth
-sandeepshetty
-Sander AKA Redsandro
-santec
-Sascha Peilicke
-satamas
-satchmorun
-sathyamoorthi
-SCLINIC\jdecker
-Scott Aikin
-Scott Goodhew
-Sebastian Zaha
-shaund
-shaun gilchrist
-Shawn A
-sheopory
-Shiv Deepak
-Shmuel Englard
-Shubham Jain
-silverwind
-snasa
-soliton4
-sonson
-spastorelli
-srajanpaliwal
-Stanislav Oaserele
-Stas Kobzar
-Stefan Borsje
-Steffen Beyer
-Steve O'Hara
-stoskov
-Taha Jahangir
-Takuji Shimokawa
-Tarmil
-tel
-tfjgeorge
-Thaddee Tyl
-TheHowl
-think
-Thomas Dvornik
-Thomas Schmid
-Tim Alby
-Tim Baumann
-Timothy Farrell
-Timothy Hatcher
-TobiasBg
-Tomas-A
-Tomas Varaneckas
-Tom Erik Støwer
-Tom MacWright
-Tony Jian
-Travis Heppe
-Triangle717
-twifkak
-Vestimir Markov
-vf
-Vincent Woo
-Volker Mische
-wenli
-Wesley Wiser
-Will Binns-Smith
-William Jamieson
-William Stein
-Willy
-Wojtek Ptak
-Xavier Mendez
-Yassin N. Hassan
-YNH Webdev
-Yunchi Luo
-Yuvi Panda
-Zachary Dremann
-Zhang Hao
-zziuni
-魏鹏刚
diff --git a/modules/yangui-resources/src/main/resources/yangui/assets/js/codemirror/CONTRIBUTING.md b/modules/yangui-resources/src/main/resources/yangui/assets/js/codemirror/CONTRIBUTING.md
deleted file mode 100644 (file)
index 1645548..0000000
+++ /dev/null
@@ -1,87 +0,0 @@
-# How to contribute
-
-- [Getting help](#getting-help-)
-- [Submitting bug reports](#submitting-bug-reports-)
-- [Contributing code](#contributing-code-)
-
-## Getting help
-
-Community discussion, questions, and informal bug reporting is done on the
-[discuss.CodeMirror forum](http://discuss.codemirror.net).
-
-## Submitting bug reports
-
-The preferred way to report bugs is to use the
-[GitHub issue tracker](http://github.com/codemirror/CodeMirror/issues). Before
-reporting a bug, read these pointers.
-
-**Note:** The issue tracker is for *bugs*, not requests for help. Questions
-should be asked on the
-[discuss.CodeMirror forum](http://discuss.codemirror.net) instead.
-
-### Reporting bugs effectively
-
-- CodeMirror is maintained by volunteers. They don't owe you anything, so be
-  polite. Reports with an indignant or belligerent tone tend to be moved to the
-  bottom of the pile.
-
-- Include information about **the browser in which the problem occurred**. Even
-  if you tested several browsers, and the problem occurred in all of them,
-  mention this fact in the bug report. Also include browser version numbers and
-  the operating system that you're on.
-
-- Mention which release of CodeMirror you're using. Preferably, try also with
-  the current development snapshot, to ensure the problem has not already been
-  fixed.
-
-- Mention very precisely what went wrong. "X is broken" is not a good bug
-  report. What did you expect to happen? What happened instead? Describe the
-  exact steps a maintainer has to take to make the problem occur. We can not
-  fix something that we can not observe.
-
-- If the problem can not be reproduced in any of the demos included in the
-  CodeMirror distribution, please provide an HTML document that demonstrates
-  the problem. The best way to do this is to go to
-  [jsbin.com](http://jsbin.com/ihunin/edit), enter it there, press save, and
-  include the resulting link in your bug report.
-
-## Contributing code
-
-- Make sure you have a [GitHub Account](https://github.com/signup/free)
-- Fork [CodeMirror](https://github.com/codemirror/CodeMirror/)
-  ([how to fork a repo](https://help.github.com/articles/fork-a-repo))
-- Make your changes
-- If your changes are easy to test or likely to regress, add tests.
-  Tests for the core go into `test/test.js`, some modes have their own
-  test suite under `mode/XXX/test.js`. Feel free to add new test
-  suites to modes that don't have one yet (be sure to link the new
-  tests into `test/index.html`).
-- Follow the general code style of the rest of the project (see
-  below). Run `bin/lint` to verify that the linter is happy.
-- Make sure all tests pass. Visit `test/index.html` in your browser to
-  run them.
-- Submit a pull request
-([how to create a pull request](https://help.github.com/articles/fork-a-repo))
-
-By contributing code to CodeMirror you
-
- - agree to license the contributed code under CodeMirror's [MIT
-   license](http://codemirror.net/LICENSE).
-
- - confirm that you have the right to contribute and license the code
-   in question. (Either you hold all rights on the code, or the rights
-   holder has explicitly granted the right to use it like this,
-   through a compatible open source license or through a direct
-   agreement with you.)
-
-### Coding standards
-
-- 2 spaces per indentation level, no tabs.
-- Include semicolons after statements.
-- Note that the linter (`bin/lint`) which is run after each commit
-  complains about unused variables and functions. Prefix their names
-  with an underscore to muffle it.
-
-- CodeMirror does *not* follow JSHint or JSLint prescribed style.
-  Patches that try to 'fix' code to pass one of these linters will be
-  unceremoniously discarded.
diff --git a/modules/yangui-resources/src/main/resources/yangui/assets/js/codemirror/LICENSE b/modules/yangui-resources/src/main/resources/yangui/assets/js/codemirror/LICENSE
deleted file mode 100644 (file)
index f4a5a4a..0000000
+++ /dev/null
@@ -1,19 +0,0 @@
-Copyright (C) 2015 by Marijn Haverbeke <marijnh@gmail.com> and others
-
-Permission is hereby granted, free of charge, to any person obtaining a copy
-of this software and associated documentation files (the "Software"), to deal
-in the Software without restriction, including without limitation the rights
-to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-copies of the Software, and to permit persons to whom the Software is
-furnished to do so, subject to the following conditions:
-
-The above copyright notice and this permission notice shall be included in
-all copies or substantial portions of the Software.
-
-THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
-THE SOFTWARE.
diff --git a/modules/yangui-resources/src/main/resources/yangui/assets/js/codemirror/README.md b/modules/yangui-resources/src/main/resources/yangui/assets/js/codemirror/README.md
deleted file mode 100644 (file)
index 38156a7..0000000
+++ /dev/null
@@ -1,12 +0,0 @@
-# CodeMirror
-[![Build Status](https://travis-ci.org/codemirror/CodeMirror.svg)](https://travis-ci.org/codemirror/CodeMirror)
-[![NPM version](https://img.shields.io/npm/v/codemirror.svg)](https://www.npmjs.org/package/codemirror)  
-[Funding status: ![maintainer happiness](https://marijnhaverbeke.nl/fund/status_s.png?again)](https://marijnhaverbeke.nl/fund/)
-
-CodeMirror is a JavaScript component that provides a code editor in
-the browser. When a mode is available for the language you are coding
-in, it will color your code, and optionally help with indentation.
-
-The project page is http://codemirror.net  
-The manual is at http://codemirror.net/doc/manual.html  
-The contributing guidelines are in [CONTRIBUTING.md](https://github.com/codemirror/CodeMirror/blob/master/CONTRIBUTING.md)
index d26c3877be295ea104c8533f472077447d87f681..a82fe9e4a859f7f519f3a7ae8aabd9606fd457e3 100644 (file)
@@ -2,23 +2,6 @@
  * Created by dakuzma on 25. 8. 2015.
  */
 require.config({
-    packages: [{
-        name: "codemirror",
-        location: "app/yangui/assets/js/codemirror",
-        main: "lib/codemirror"
-    }],
-    paths: {
-        'codeMirror-showHint' : 'app/yangui/assets/js/codemirror/addon/hint/show-hint',
-        'codeMirror-yanguiJsonHint' : 'app/yangui/assets/js/codemirror/addon/hint/yangui-json-hint',
-        'codeMirror-javascriptMode' : 'app/yangui/assets/js/codemirror/mode/javascript/javascript',
-        'codeMirror-matchBrackets' : 'app/yangui/assets/js/codemirror/addon/edit/matchbrackets'
-    },
-    shim:{
-        'codeMirros_showHint': ['codemirror'],
-        'codeMirros_javascriptHint': ['codemirror'],
-        'codeMirror_javascriptMode': ['codemirror'],
-        'codeMirror_matchBrackets': ['codemirror']
-    }
 });
 
 define(['app/yangui/yangui.module']);
index 6e0ed54406d3599c4be63b5cebb781d3623bbafb..80468bb1b53a0964f259b01cc6fed081252b220b 100644 (file)
@@ -1,10 +1,3 @@
-/*PLUGINS importing*/\r
-@import 'assets/js/codemirror/lib/codemirror.less';\r
-@import 'assets/js/codemirror/theme/eclipse.less';\r
-@import 'assets/js/codemirror/theme/eclipse-disabled.less';\r
-@import 'assets/js/codemirror/addon/hint/show-hint.less';\r
-/*PLUGINS importing END*/\r
-\r
 @iconsNewRootPath : '../src/app/yangui/assets/images/';\r
 \r
 /******** WINDOW SCROLLBARS *****/\r
@@ -87,7 +80,7 @@
 }*/\r
 \r
 .previewContainer{\r
-  min-width:204px; \r
+  min-width:204px;\r
   min-height:97px;\r
 }\r
 \r
@@ -221,7 +214,7 @@ input[type="file"].upload-collection{
 \r
 /* --------------------------------------------------------------------------------- COMMON OWN RULES */\r
 .opacityDeph(@opacity: 0.5){\r
-  -ms-filter: ~"'progid:DXImageTransform.Microsoft.Alpha(Opacity=" @opacity*100 ~")'";  \r
+  -ms-filter: ~"'progid:DXImageTransform.Microsoft.Alpha(Opacity=" @opacity*100 ~")'";\r
   filter: ~"alpha(opacity=" @opacity*100 ~")";\r
   -moz-opacity: @opacity;\r
   -khtml-opacity: @opacity;\r
@@ -300,6 +293,19 @@ input[type="file"].upload-collection{
 /* --------------------------------------------------------------------------------- YANG UI */\r
 .yangUIwrapper{\r
 \r
+  input[type=text]{\r
+    background-color: #58595B;\r
+    color: white;\r
+  }\r
+\r
+  span{\r
+    color: white;\r
+  }\r
+\r
+  .yangUIwrapper .CodeMirror span{\r
+    color: auto;\r
+  }\r
+\r
   ::-webkit-scrollbar {\r
     width: 10px;\r
     height: 10px;\r
@@ -520,7 +526,7 @@ label.classic{
     .roundedCorners(0px);\r
     border: 0;\r
   }\r
-  \r
+\r
   label.classic{\r
     min-width: 90px;\r
   }\r
@@ -628,7 +634,7 @@ div.requestActions{
 \r
   .historyRequestBox{\r
     position: relative;\r
-    \r
+\r
     .changeGroup{\r
         left: -365px;\r
     }\r
@@ -840,7 +846,7 @@ div.mountPoints{
       .scroll{\r
         overflow-y: auto;\r
         position: relative;\r
-        height: calc(~"100% - 50px"); \r
+        height: calc(~"100% - 50px");\r
       }\r
 \r
 \r
@@ -898,12 +904,12 @@ div.mountPoints{
             span{\r
               color: auto;\r
             }\r
-            \r
+\r
             pre span{\r
                 color: auto;\r
             }\r
-            \r
-            \r
+\r
+\r
             textarea{\r
               width: 100%;\r
               min-height: 50px;\r
@@ -927,7 +933,7 @@ div.mountPoints{
                 margin-bottom: 1px;\r
                 font-size: 12px;\r
               }\r
-              \r
+\r
               span{\r
                 color: @text-color;\r
               }\r
@@ -969,13 +975,13 @@ div.mountPoints{
 \r
 \r
     .reqParams {\r
-          \r
+\r
       .thdiv{\r
         .rh-col3{\r
           width: calc(~"100% - 450px");\r
         }\r
       }\r
-        \r
+\r
       .rh-col2{\r
         width: 235px;\r
       }\r
@@ -1190,7 +1196,7 @@ i.icon-spinner{
   .listButtonWrapper{\r
     margin: 2px 15px 0 5px;\r
     .inlineBlock;\r
-    \r
+\r
     button.yangButton{\r
       margin: 0px;\r
     }\r
@@ -1252,17 +1258,17 @@ i.icon-spinner{
   &.containerBullet{\r
 /*    margin: 0 0px 0 -14px;\r
     line-height: 25px;*/\r
-    top: -25px; \r
+    top: -25px;\r
     left: -25px;\r
   }\r
 }\r
 \r
 .tooltip-inner{\r
   color: #fff;\r
-  white-space: pre-wrap;      /* CSS3 */   \r
-  white-space: -moz-pre-wrap; /* Firefox */    \r
-  white-space: -pre-wrap;     /* Opera <7 */   \r
-  white-space: -o-pre-wrap;   /* Opera 7 */    \r
+  white-space: pre-wrap;      /* CSS3 */\r
+  white-space: -moz-pre-wrap; /* Firefox */\r
+  white-space: -pre-wrap;     /* Opera <7 */\r
+  white-space: -o-pre-wrap;   /* Opera 7 */\r
   word-wrap: break-word;      /* IE */\r
 }\r
 \r
@@ -1523,7 +1529,7 @@ button, div{
     cursor: se-resize;\r
   }\r
 }\r
-  \r
+\r
 \r
 .ui-resizable-s {\r
   cursor: s-resize;\r
index 3bc717391de29b68fd3775eea6c07c3d2c289918..0d718e2891bfe5daeb95f291aa132cb85e952d60 100644 (file)
@@ -8,7 +8,7 @@ var modules = [
         'jquery-ui',\r
         'codemirror',\r
         'codeMirror-showHint',\r
-        'codeMirror-yanguiJsonHint',\r
+        'codeMirror-jsonParametersHint',\r
         'codeMirror-javascriptMode',\r
         'codeMirror-matchBrackets',\r
         'ngClip',\r
index 5b9bc3abbf0ea2ff3b7fe2a2bfe801669cf1ec81..8a834f5b3003ee0737b0e24bd5257d095d7234fe 100644 (file)
@@ -12,7 +12,7 @@
   <parent>
     <groupId>org.opendaylight.dlux</groupId>
     <artifactId>dlux-parent</artifactId>
-    <version>0.4.0-SNAPSHOT</version>
+    <version>0.5.0-SNAPSHOT</version>
     <relativePath>../../</relativePath>
   </parent>
 
diff --git a/pom.xml b/pom.xml
index db8b6f0b7804b7a0cf06df1cd5d54a50253a3d4d..18310eafbc22ac6465cdb5d036aa7fafaa50cd16 100644 (file)
--- a/pom.xml
+++ b/pom.xml
@@ -4,68 +4,70 @@
   <parent>
     <groupId>org.opendaylight.odlparent</groupId>
     <artifactId>odlparent</artifactId>
-    <version>1.7.0-SNAPSHOT</version>
+    <version>1.8.0-SNAPSHOT</version>
     <relativePath></relativePath>
   </parent>
 
-    <modelVersion>4.0.0</modelVersion>
-    <groupId>org.opendaylight.dlux</groupId>
-    <artifactId>dlux-parent</artifactId>
-    <version>0.4.0-SNAPSHOT</version>
-    <packaging>pom</packaging>
-    <name>dlux</name> <!-- Used by Sonar to set project name -->
+  <modelVersion>4.0.0</modelVersion>
+  <groupId>org.opendaylight.dlux</groupId>
+  <artifactId>dlux-parent</artifactId>
+  <version>0.5.0-SNAPSHOT</version>
+  <packaging>pom</packaging>
+  <name>dlux</name> <!-- Used by Sonar to set project name -->
 
-    <properties>
-      <commons.opendaylight.version>1.7.0-SNAPSHOT</commons.opendaylight.version>
-      <loader.resources.version>0.3.0-SNAPSHOT</loader.resources.version>
-      <core.resources.version>0.3.0-SNAPSHOT</core.resources.version>
-      <node.resources.version>0.3.0-SNAPSHOT</node.resources.version>
-      <connection_manager.resources.version>0.3.0-SNAPSHOT</connection_manager.resources.version>
-      <container.resources.version>0.3.0-SNAPSHOT</container.resources.version>
-      <flow.resources.version>0.3.0-SNAPSHOT</flow.resources.version>
-      <network.resources.version>0.3.0-SNAPSHOT</network.resources.version>
-      <topology.resources.version>0.3.0-SNAPSHOT</topology.resources.version>
-      <yangui.resources.version>0.3.0-SNAPSHOT</yangui.resources.version>
-      <yangvisualizer.resources.version>0.3.0-SNAPSHOT</yangvisualizer.resources.version>
-      <common.authentication.resources.version>0.3.0-SNAPSHOT</common.authentication.resources.version>
-      <common.general.resources.version>0.3.0-SNAPSHOT</common.general.resources.version>
-      <common.navigation.resources.version>0.3.0-SNAPSHOT</common.navigation.resources.version>
-      <common.layout.resources.version>0.3.0-SNAPSHOT</common.layout.resources.version>
-      <common.topbar.resources.version>0.3.0-SNAPSHOT</common.topbar.resources.version>
-      <common.login.resources.version>0.3.0-SNAPSHOT</common.login.resources.version>
-      <common.yangutils.resources.version>0.3.0-SNAPSHOT</common.yangutils.resources.version>
-      <common.sigmatopology.resources.version>0.3.0-SNAPSHOT</common.sigmatopology.resources.version>
-      <restconf.version>1.4.0-SNAPSHOT</restconf.version>
-      <l2switch.version>0.4.0-SNAPSHOT</l2switch.version>
-      <mdsal.version>1.4.0-SNAPSHOT</mdsal.version>
-      <branding.version>1.3.0-SNAPSHOT</branding.version>
-      <karaf.resources.version>1.7.0-SNAPSHOT</karaf.resources.version>
-      <feature.l2switch.version>0.4.0-SNAPSHOT</feature.l2switch.version>
-      <feature.aaa.version>0.4.0-SNAPSHOT</feature.aaa.version>
-      <feature.openflowplugin.version>0.3.0-SNAPSHOT</feature.openflowplugin.version>
+  <properties>
+    <commons.opendaylight.version>1.8.0-SNAPSHOT</commons.opendaylight.version>
+    <loader.resources.version>0.5.0-SNAPSHOT</loader.resources.version>
+    <core.resources.version>0.5.0-SNAPSHOT</core.resources.version>
+    <node.resources.version>0.5.0-SNAPSHOT</node.resources.version>
+    <connection_manager.resources.version>0.5.0-SNAPSHOT</connection_manager.resources.version>
+    <container.resources.version>0.5.0-SNAPSHOT</container.resources.version>
+    <flow.resources.version>0.5.0-SNAPSHOT</flow.resources.version>
+    <network.resources.version>0.5.0-SNAPSHOT</network.resources.version>
+    <topology.resources.version>0.5.0-SNAPSHOT</topology.resources.version>
+    <yangui.resources.version>0.5.0-SNAPSHOT</yangui.resources.version>
+    <yangman.resources.version>0.5.0-SNAPSHOT</yangman.resources.version>
+    <yangvisualizer.resources.version>0.5.0-SNAPSHOT</yangvisualizer.resources.version>
+    <common.authentication.resources.version>0.5.0-SNAPSHOT</common.authentication.resources.version>
+    <common.general.resources.version>0.5.0-SNAPSHOT</common.general.resources.version>
+    <common.navigation.resources.version>0.5.0-SNAPSHOT</common.navigation.resources.version>
+    <common.layout.resources.version>0.5.0-SNAPSHOT</common.layout.resources.version>
+    <common.topbar.resources.version>0.5.0-SNAPSHOT</common.topbar.resources.version>
+    <common.login.resources.version>0.5.0-SNAPSHOT</common.login.resources.version>
+    <common.yangutils.resources.version>0.5.0-SNAPSHOT</common.yangutils.resources.version>
+    <common.sigmatopology.resources.version>0.5.0-SNAPSHOT</common.sigmatopology.resources.version>
+    <restconf.version>1.5.0-SNAPSHOT</restconf.version>
+    <l2switch.version>0.5.0-SNAPSHOT</l2switch.version>
+    <mdsal.version>1.5.0-SNAPSHOT</mdsal.version>
+    <branding.version>1.4.0-SNAPSHOT</branding.version>
+    <karaf.resources.version>1.8.0-SNAPSHOT</karaf.resources.version>
+    <feature.l2switch.version>0.5.0-SNAPSHOT</feature.l2switch.version>
+    <feature.aaa.version>0.5.0-SNAPSHOT</feature.aaa.version>
+    <feature.openflowplugin.version>0.4.0-SNAPSHOT</feature.openflowplugin.version>
 
-      <feature.test.version>1.7.0-SNAPSHOT</feature.test.version>
-      <feature.mdsal.version>1.4.0-SNAPSHOT</feature.mdsal.version>
-      <feature.dlux.version>0.4.0-SNAPSHOT</feature.dlux.version>
-      <feature.flow.version>1.4.0-SNAPSHOT</feature.flow.version>
-      <feature.yangtools.version>1.0.0-SNAPSHOT</feature.yangtools.version>
-      <apache.felix.osgi.compendium.version>1.4.0</apache.felix.osgi.compendium.version>
-      <javax.servlet-api.version>3.0.1</javax.servlet-api.version>
-      <karaf.empty.version>1.7.0-SNAPSHOT</karaf.empty.version>
-    </properties>
+    <feature.test.version>1.8.0-SNAPSHOT</feature.test.version>
+    <feature.mdsal.version>1.5.0-SNAPSHOT</feature.mdsal.version>
+    <feature.dlux.version>0.5.0-SNAPSHOT</feature.dlux.version>
+    <feature.flow.version>1.5.0-SNAPSHOT</feature.flow.version>
+    <feature.yangtools.version>1.1.0-SNAPSHOT</feature.yangtools.version>
+    <apache.felix.osgi.compendium.version>1.4.0</apache.felix.osgi.compendium.version>
+    <javax.servlet-api.version>3.0.1</javax.servlet-api.version>
+    <karaf.empty.version>1.8.0-SNAPSHOT</karaf.empty.version>
+  </properties>
 
-    <modules>
-       <module>modules</module>
-       <module>dlux-web</module>
-       <module>loader/api</module>
-       <module>loader/impl</module>
-       <module>bundles</module>
-       <module>features</module>
-       <module>archetype</module>
-    </modules>
+  <modules>
+    <module>modules</module>
+    <module>dlux-web</module>
+    <module>loader/api</module>
+    <module>loader/impl</module>
+    <module>bundles</module>
+    <module>features</module>
+    <module>archetype</module>
+  </modules>
 
   <scm>
-    <connection>scm:git:ssh://git.opendaylight.org:29418/dlux.git</connection>     <developerConnection>scm:git:ssh://git.opendaylight.org:29418/dlux.git</developerConnection>
+    <connection>scm:git:ssh://git.opendaylight.org:29418/dlux.git</connection>
+    <developerConnection>scm:git:ssh://git.opendaylight.org:29418/dlux.git</developerConnection>
     <tag>HEAD</tag>
     <url>https://wiki.opendaylight.org/view/OpenDaylight_dlux:Main</url>
   </scm>