atlas-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From suma...@apache.org
Subject incubator-atlas git commit: ATLAS-188 Provide Ability to Add Tag to Entity (sanjayp via sumasai)
Date Sat, 10 Oct 2015 04:34:32 GMT
Repository: incubator-atlas
Updated Branches:
  refs/heads/master 461a2a4e3 -> 4f61fff2b


ATLAS-188 Provide Ability to Add Tag to Entity (sanjayp via sumasai)


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

Branch: refs/heads/master
Commit: 4f61fff2b7467d9fa82c2dd7f81624b2ab885281
Parents: 461a2a4
Author: Suma Shivaprasad <sumasai.shivaprasad@gmail.com>
Authored: Sat Oct 10 10:04:01 2015 +0530
Committer: Suma Shivaprasad <sumasai.shivaprasad@gmail.com>
Committed: Sat Oct 10 10:04:01 2015 +0530

----------------------------------------------------------------------
 dashboard/public/css/details.css                |   2 +-
 dashboard/public/css/tags.css                   |  51 +++++++
 dashboard/public/index.html                     |   1 +
 dashboard/public/js/app.js                      |   4 +-
 .../public/modules/details/detailsController.js |   4 +-
 .../public/modules/details/detailsResource.js   |   4 +
 .../public/modules/details/views/details.html   |   1 +
 .../public/modules/search/views/search.html     |   2 +-
 .../tags/definition/definitionTagsController.js |  63 +++++++++
 .../tags/definition/definitionTagsModule.js     |  21 +++
 .../tags/definition/tagAttributeDefinition.js   |  33 +++++
 .../modules/tags/definition/views/add.html      | 134 +++++++++++++++++++
 .../tags/instance/createTagController.js        |  72 ++++++++++
 .../tags/instance/instanceTagsController.js     |  40 ++++++
 .../modules/tags/instance/instanceTagsModule.js |  21 +++
 .../modules/tags/instance/views/createTag.html  |  42 ++++++
 .../modules/tags/instance/views/tags.html       |  28 ++++
 .../modules/tags/tagAttributeDefinition.js      |  33 -----
 dashboard/public/modules/tags/tagClasses.js     |  11 ++
 dashboard/public/modules/tags/tagsController.js |  63 ---------
 dashboard/public/modules/tags/tagsRoutes.js     |  19 ++-
 dashboard/public/modules/tags/views/add.html    | 134 -------------------
 22 files changed, 546 insertions(+), 237 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-atlas/blob/4f61fff2/dashboard/public/css/details.css
----------------------------------------------------------------------
diff --git a/dashboard/public/css/details.css b/dashboard/public/css/details.css
index 156d5f6..6c62bcf 100644
--- a/dashboard/public/css/details.css
+++ b/dashboard/public/css/details.css
@@ -18,4 +18,4 @@
 
 .tab-content .table-bordered {
     border-top: none;
-}
\ No newline at end of file
+}

http://git-wip-us.apache.org/repos/asf/incubator-atlas/blob/4f61fff2/dashboard/public/css/tags.css
----------------------------------------------------------------------
diff --git a/dashboard/public/css/tags.css b/dashboard/public/css/tags.css
new file mode 100644
index 0000000..21aa89d
--- /dev/null
+++ b/dashboard/public/css/tags.css
@@ -0,0 +1,51 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+.add-tag {
+    text-decoration: underline;
+}
+
+.input-spacing{
+	padding-bottom: 10px!important;
+}
+
+.create-tag-entity .modal-footer{
+	border-top: 0;
+}
+
+.tag-list{
+	border:1px solid #ddd;
+	padding:10px;
+	background-color: #F5F5F5;
+}
+
+.tag-list ul{
+	padding-left: 0px;
+}
+
+.error{
+	color:red;
+}
+
+.tag-list ul li{
+	display: inline;
+	line-height: 30px;
+	border:none;
+	padding: 0px;
+	background-color: inherit;
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-atlas/blob/4f61fff2/dashboard/public/index.html
----------------------------------------------------------------------
diff --git a/dashboard/public/index.html b/dashboard/public/index.html
index 5ce839d..4190b5c 100644
--- a/dashboard/public/index.html
+++ b/dashboard/public/index.html
@@ -34,6 +34,7 @@
   <link rel="stylesheet" href="/css/common.css">
   <link rel="stylesheet" href="/css/details.css">
   <link rel="stylesheet" href="/css/lineage.css">
+  <link rel="stylesheet" href="/css/tags.css">
   <link rel="stylesheet" href="http://maxcdn.bootstrapcdn.com/bootstrap/3.3.4/css/bootstrap.min.css">
  </head>
 

http://git-wip-us.apache.org/repos/asf/incubator-atlas/blob/4f61fff2/dashboard/public/js/app.js
----------------------------------------------------------------------
diff --git a/dashboard/public/js/app.js b/dashboard/public/js/app.js
index 82171c6..3ef1794 100644
--- a/dashboard/public/js/app.js
+++ b/dashboard/public/js/app.js
@@ -27,7 +27,9 @@ angular.module('dgc', ['ngCookies',
     'dgc.about',
     'dgc.search',
     'dgc.navigation',
-    'dgc.tags'
+    'dgc.tags',
+    'dgc.tags.instance',
+    'dgc.tags.definition'
 ]);
 
 angular.module('dgc.system', ['dgc.system.notification']);

http://git-wip-us.apache.org/repos/asf/incubator-atlas/blob/4f61fff2/dashboard/public/modules/details/detailsController.js
----------------------------------------------------------------------
diff --git a/dashboard/public/modules/details/detailsController.js b/dashboard/public/modules/details/detailsController.js
index c469c37..538d262 100644
--- a/dashboard/public/modules/details/detailsController.js
+++ b/dashboard/public/modules/details/detailsController.js
@@ -36,7 +36,6 @@ angular.module('dgc.details').controller('DetailsController', ['$window', '$scop
         $scope.isNumber = angular.isNumber;
 
         $scope.isString = angular.isString;
-
         $scope.onActivate = function tabActivate(tabname) {
             $scope.$broadcast('render-lineage', {
                 type: tabname,
@@ -47,6 +46,5 @@ angular.module('dgc.details').controller('DetailsController', ['$window', '$scop
         $scope.goBack = function() {
             $window.history.back();
         };
-
     }
-]);
\ No newline at end of file
+]);

http://git-wip-us.apache.org/repos/asf/incubator-atlas/blob/4f61fff2/dashboard/public/modules/details/detailsResource.js
----------------------------------------------------------------------
diff --git a/dashboard/public/modules/details/detailsResource.js b/dashboard/public/modules/details/detailsResource.js
index a559e6f..a765595 100644
--- a/dashboard/public/modules/details/detailsResource.js
+++ b/dashboard/public/modules/details/detailsResource.js
@@ -28,6 +28,10 @@ angular.module('dgc.details').factory('DetailsResource', ['$resource', function(
                 }
             },
             responseType: 'json'
+        },
+        saveTag: {
+            method: 'POST',
+            url: '/api/atlas/entity/:id/traits'
         }
     });
 

http://git-wip-us.apache.org/repos/asf/incubator-atlas/blob/4f61fff2/dashboard/public/modules/details/views/details.html
----------------------------------------------------------------------
diff --git a/dashboard/public/modules/details/views/details.html b/dashboard/public/modules/details/views/details.html
index 26d81ec..f53f94d 100644
--- a/dashboard/public/modules/details/views/details.html
+++ b/dashboard/public/modules/details/views/details.html
@@ -41,6 +41,7 @@
                     </tr>
                     </tbody>
                 </table>
+                <ng-include  src="'/modules/tags/instance/views/tags.html'"/>
             </tab>
             <tab data-heading="Schema" data-ng-if="isTable"><ng-include src="'/modules/details/views/schema.html'"/></tab>
             <!-- <tab data-heading="Output" data-ng-if="isTable" data-disable="!tableName" data-select="onActivate('outputs')"><ng-include data-table-type="outputs" src="'/modules/lineage/views/lineage.html'"/></tab>

http://git-wip-us.apache.org/repos/asf/incubator-atlas/blob/4f61fff2/dashboard/public/modules/search/views/search.html
----------------------------------------------------------------------
diff --git a/dashboard/public/modules/search/views/search.html b/dashboard/public/modules/search/views/search.html
index 389364d..d5bc6c6 100644
--- a/dashboard/public/modules/search/views/search.html
+++ b/dashboard/public/modules/search/views/search.html
@@ -55,7 +55,7 @@
                 <a href ng-show="isCollapsed && (keyLength > 4)" ng-click="doToggle($event,isCollapsed)">..show more</a>
                 <a href ng-show="!isCollapsed" ng-click="doToggle($event,isCollapsed)">..show less</a>
 
-                <h5 ng-show="!dataTransitioned">Tags : <a ng-repeat="(key, value) in result['$traits$']" data-ui-sref="search({query: key})">{{key}}</a></h5>
+                <h5 ng-show="!dataTransitioned">Tags : <a ng-repeat="(key, value) in result['$traits$']" data-ui-sref="search({query: key})">{{key}}<span ng-show="!{{$last}}">,</span> </a></h5>
 
             </li>
         </ul>

http://git-wip-us.apache.org/repos/asf/incubator-atlas/blob/4f61fff2/dashboard/public/modules/tags/definition/definitionTagsController.js
----------------------------------------------------------------------
diff --git a/dashboard/public/modules/tags/definition/definitionTagsController.js b/dashboard/public/modules/tags/definition/definitionTagsController.js
new file mode 100755
index 0000000..099695d
--- /dev/null
+++ b/dashboard/public/modules/tags/definition/definitionTagsController.js
@@ -0,0 +1,63 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+'use strict';
+
+angular.module('dgc.tags.definition').controller('DefinitionTagsController', ['$scope', '$resource', '$state', '$stateParams', 'lodash', 'AttributeDefinition', 'TagClasses', 'TagsResource', 'NotificationService',
+    function($scope, $resource, $state, $stateParams, _, AttributeDefinition, Categories, TagsResource, NotificationService) {
+        $scope.categoryList = Categories;
+        $scope.category = 'TRAIT';
+        $scope.tagModel = {
+            typeName: null,
+            attributeDefinitions: []
+        };
+
+        $scope.addAttribute = function AddAttribute() {
+            $scope.tagModel.attributeDefinitions.push(AttributeDefinition.getModel());
+        };
+
+        $scope.categoryChange = function CategorySwitched() {
+            $scope.categoryInst = Categories[$scope.category].clearTags();
+        };
+
+        $scope.save = function saveTag(form) {
+            $scope.savedTag = null;
+            if (form.$valid) {
+                $scope.categoryInst = Categories[$scope.category];
+                $scope.categoryInst.clearTags().addTag($scope.tagModel);
+
+                NotificationService.reset();
+                $scope.saving = true;
+
+                TagsResource.save($scope.categoryInst.toJson()).$promise
+                    .then(function TagCreateSuccess() {
+                        NotificationService.info('"' + $scope.tagModel.typeName + '" has been created', false);
+                        return TagsResource.get({
+                            id: $scope.tagModel.typeName
+                        }).$promise;
+                    }).then(function TagFound(res) {
+                        $scope.savedTag = JSON.parse(res.definition);
+                    }).catch(function TagCreateFailed(error) {
+                        NotificationService.error(error.data.error, false);
+                    }).finally(function() {
+                        $scope.saving = false;
+                    });
+            }
+        };
+    }
+]);

http://git-wip-us.apache.org/repos/asf/incubator-atlas/blob/4f61fff2/dashboard/public/modules/tags/definition/definitionTagsModule.js
----------------------------------------------------------------------
diff --git a/dashboard/public/modules/tags/definition/definitionTagsModule.js b/dashboard/public/modules/tags/definition/definitionTagsModule.js
new file mode 100644
index 0000000..eb2059f
--- /dev/null
+++ b/dashboard/public/modules/tags/definition/definitionTagsModule.js
@@ -0,0 +1,21 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+'use strict';
+
+angular.module('dgc.tags.definition', []);

http://git-wip-us.apache.org/repos/asf/incubator-atlas/blob/4f61fff2/dashboard/public/modules/tags/definition/tagAttributeDefinition.js
----------------------------------------------------------------------
diff --git a/dashboard/public/modules/tags/definition/tagAttributeDefinition.js b/dashboard/public/modules/tags/definition/tagAttributeDefinition.js
new file mode 100644
index 0000000..3c2094d
--- /dev/null
+++ b/dashboard/public/modules/tags/definition/tagAttributeDefinition.js
@@ -0,0 +1,33 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * 'License'); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an 'AS IS' BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+'use strict';
+
+angular.module('dgc.tags.definition').service('AttributeDefinition', function Attribute() {
+    this.getModel = function getJson() {
+        return {
+            name: null,
+            dataTypeName: 'string',
+            multiplicity: 'optional',
+            isComposite: false,
+            isUnique: false,
+            isIndexable: true,
+            reverseAttributeName: null
+        };
+    };
+});

http://git-wip-us.apache.org/repos/asf/incubator-atlas/blob/4f61fff2/dashboard/public/modules/tags/definition/views/add.html
----------------------------------------------------------------------
diff --git a/dashboard/public/modules/tags/definition/views/add.html b/dashboard/public/modules/tags/definition/views/add.html
new file mode 100755
index 0000000..7f4f82a
--- /dev/null
+++ b/dashboard/public/modules/tags/definition/views/add.html
@@ -0,0 +1,134 @@
+<!--
+  ~ Licensed to the Apache Software Foundation (ASF) under one
+  ~ or more contributor license agreements.  See the NOTICE file
+  ~ distributed with this work for additional information
+  ~ regarding copyright ownership.  The ASF licenses this file
+  ~ to you under the Apache License, Version 2.0 (the
+  ~ "License"); you may not use this file except in compliance
+  ~ with the License.  You may obtain a copy of the License at
+  ~
+  ~     http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+  -->
+<div class="container">
+    <div class="appForm" data-ng-controller="DefinitionTagsController">
+        <h4>Tag Definition</h4>
+
+        <form data-name="tagForm" class="form-horizontal" novalidate role="form">
+            <fieldset data-ng-disabled="saving">
+
+                <div class="form-group hide">
+                    <label for="category" class="col-sm-2 control-label">Category</label>
+
+                    <div class="col-sm-10">
+                        <select class="form-control" id="category" name="category" data-ng-model="category" data-ng-change="categoryChange()" required>
+                            <option value="{{key}}" data-ng-repeat="(key, value) in categoryList" ng-selected="{{key===category}}">{{key}}</option>
+                        </select>
+                    </div>
+                </div>
+                <div class="form-group" data-ng-class="{'has-error': tagForm.typeName.$invalid && tagForm.typeName.$dirty}">
+                    <label for="typeName" class="col-sm-2 control-label">Tag Name</label>
+
+                    <div class="col-sm-10">
+                        <input type="text" class="form-control" name="typeName" id="typeName" placeholder="Tag Name" data-ng-model="tagModel.typeName" required/>
+                    </div>
+                </div>
+                <ng-form name="attributeForm">
+                    <div class="form-group" data-ng-class="{'has-error': attributeForm.name.$invalid && attributeForm.name.$dirty}"
+                         data-ng-repeat-start="attribute in tagModel.attributeDefinitions">
+                        <label for="attributeId_{{$index}}" class="col-sm-2 control-label">Attribute name</label>
+
+                        <div class="col-sm-10">
+                          <!--   <div class="input-group"> -->
+                                <input type="text" class="form-control" name="name" id="attributeId_{{$index}}" placeholder="Attribute name" data-ng-model="attribute.name"
+                                       required/>
+                             <!--    <i class="input-group-addon fa fa-2x" data-ng-class="{'fa-angle-double-down':!attribute.$$show, 'fa-angle-double-up':attribute.$$show}"
+                                   data-ng-click="attribute.$$show=!attribute.$$show"></i> -->
+                           <!--  </div> -->
+                        </div>
+                    </div>
+                    <div class="form-group" data-ng-class="{'has-error': attributeForm.name.$invalid && attributeForm.name.$dirty}" data-ng-show="attribute.$$show">
+                        <label for="attributeDatatype_{{$index}}" class="col-sm-2 control-label">Data Type Name</label>
+
+                        <div class="col-sm-10">
+                            <input type="text" class="form-control" name="name" id="attributeDatatype_{{$index}}" placeholder="dataTypeName"
+                                   data-ng-model="attribute.dataTypeName"/>
+                        </div>
+                    </div>
+                    <div class="form-group" data-ng-class="{'has-error': attributeForm.name.$invalid && attributeForm.name.$dirty}" data-ng-show="attribute.$$show">
+                        <label for="attributeMultiplicity_{{$index}}" class="col-sm-2 control-label">Multiplicity</label>
+
+                        <div class="col-sm-10">
+                            <input type="text" class="form-control" name="name" id="attributeMultiplicity_{{$index}}" placeholder="multiplicity"
+                                   data-ng-model="attribute.multiplicity"/>
+                        </div>
+                    </div>
+
+                    <div class="form-group" data-ng-class="{'has-error': attributeForm.name.$invalid && attributeForm.name.$dirty}" data-ng-show="attribute.$$show">
+                        <label for="attributeIscomposite_{{$index}}" class="col-sm-2 control-label">isComposite</label>
+
+                        <div class="col-sm-10">
+                            <span class ="btnToggle">
+                            <a class="btn-sm " ng-class="{true: 'btn-primary'}[attribute.isComposite]" ng-click="attribute.isComposite = true">true </a>
+                            <a class="btn-sm " ng-class="{false: 'btn-danger'}[attribute.isComposite]" ng-click="attribute.isComposite = false"> false </a>
+
+                                </span>
+                        </div>
+                    </div>
+                    <div class="form-group" data-ng-class="{'has-error': attributeForm.name.$invalid && attributeForm.name.$dirty}" data-ng-show="attribute.$$show">
+                        <label for="attributeIsunique_{{$index}}" class="col-sm-2 control-label">isUnique</label>
+
+                        <div class="col-sm-10">
+                            <span class ="btnToggle">
+                            <a class="btn-sm " ng-class="{true: 'btn-primary'}[attribute.isUnique]" ng-click="attribute.isUnique = true">true </a>
+                            <a class="btn-sm " ng-class="{false: 'btn-danger'}[attribute.isUnique]" ng-click="attribute.isUnique = false"> false </a>
+
+                                </span>
+                        </div>
+                    </div>
+                    <div class="form-group" data-ng-class="{'has-error': attributeForm.name.$invalid && attributeForm.name.$dirty}" data-ng-show="attribute.$$show">
+                        <label for="attributeIndexable_{{$index}}" class="col-sm-2 control-label">isIndexable</label>
+
+                        <div class="col-sm-10">
+                            <span class ="btnToggle">
+                            <a class="btn-sm " ng-class="{true: 'btn-primary'}[attribute.isIndexable]" ng-click="attribute.isIndexable = true">true </a>
+                            <a class="btn-sm " ng-class="{false: 'btn-danger'}[attribute.isIndexable]" ng-click="attribute.isIndexable = false"> false </a>
+
+                                </span>
+                        </div>
+                    </div>
+
+
+                    <div class="form-group" data-ng-class="{'has-error': attributeForm.name.$invalid && attributeForm.name.$dirty}" data-ng-show="attribute.$$show"
+                         data-ng-repeat-end>
+                        <label for="attributeReverseName_{{$index}}" class="col-sm-2 control-label">reverseAttributeName</label>
+
+                        <div class="col-sm-10">
+                            <input type="text" class="form-control" name="reverseName" id="attributeReverseName_{{$index}}" placeholder="reverseAttributeName"
+                                   data-ng-model="attribute.reverseAttributeName"/>
+                        </div>
+                    </div>
+                </ng-form>
+                <div class="form-group text-right">
+                    <div class="col-sm-offset-2 col-sm-10">
+
+                        <button data-ng-click="addAttribute()" class="btn btn-default">Add Attribute</button>
+                    </div>
+                </div>
+                <div class="form-group">
+                    <div class="col-sm-offset-2 col-sm-10">
+                        <button type="submit" data-ng-click="save(tagForm)" data-ng-disabled="tagForm.$invalid" class="btn btn-default">Save</button>
+                    </div>
+                </div>
+            </fieldset>
+        </form>
+        <div class="row" data-ng-show="savedTag">
+            <pre>{{savedTag | json}}</pre>
+        </div>
+    </div>
+</div>
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-atlas/blob/4f61fff2/dashboard/public/modules/tags/instance/createTagController.js
----------------------------------------------------------------------
diff --git a/dashboard/public/modules/tags/instance/createTagController.js b/dashboard/public/modules/tags/instance/createTagController.js
new file mode 100644
index 0000000..e6df24c
--- /dev/null
+++ b/dashboard/public/modules/tags/instance/createTagController.js
@@ -0,0 +1,72 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+'use strict';
+
+angular.module('dgc.tags.instance').controller('CreateTagController', ['$scope', 'DetailsResource', '$modalInstance', 'typesList', 'lodash', 'TagsResource', '$stateParams', '$rootScope', 'TagClasses', 'NotificationService',
+    function($scope, DetailsResource, $modalInstance, typesList, _, TagsResource, $stateParams, $rootScope, Categories, NotificationService) {
+        if (typesList) {
+            $scope.typesList = typesList;
+        }
+        $scope.categoryList = Categories;
+        $scope.category = 'TRAIT';
+
+        $scope.getAttributeDefinations = function() {
+            TagsResource.get({
+                id: $scope.selectedType
+            }, function(data) {
+                var instanceType = Categories[$scope.category].instanceInfo();
+                if (instanceType) {
+                    var traitTypes = angular.fromJson(data.definition)[instanceType][0];
+                    if (traitTypes) {
+                        $scope.propertiesList = {};
+                        $scope.isRequired = {};
+                        _.each(traitTypes.attributeDefinitions, function(value) {
+                            $scope.propertiesList[value.name] = '';
+                            $scope.isRequired[value.name] = value.isRequired;
+                        });
+                    }
+                }
+
+            });
+        };
+        $scope.ok = function(tagDefinitionform) {
+            if (tagDefinitionform.$valid) {
+                var requestObject = {
+                    "jsonClass": "org.apache.atlas.typesystem.json.InstanceSerialization$_Struct",
+                    "typeName": $scope.selectedType,
+                    "values": $scope.propertiesList
+                };
+                DetailsResource.saveTag({
+                    id: $stateParams.id
+                }, requestObject).$promise.then(function() {
+                    $rootScope.$broadcast('refreshResourceData');
+                    NotificationService.info('Tag "' + $scope.selectedType + '" has been added to entity', true);
+                    $modalInstance.close(true);
+                }).catch(function(err) {
+                    $scope.isError = true;
+                    $scope.error = err.data.error;
+                });
+            }
+        };
+
+        $scope.cancel = function() {
+            $modalInstance.dismiss('cancel');
+        };
+    }
+]);

http://git-wip-us.apache.org/repos/asf/incubator-atlas/blob/4f61fff2/dashboard/public/modules/tags/instance/instanceTagsController.js
----------------------------------------------------------------------
diff --git a/dashboard/public/modules/tags/instance/instanceTagsController.js b/dashboard/public/modules/tags/instance/instanceTagsController.js
new file mode 100644
index 0000000..663a8d0
--- /dev/null
+++ b/dashboard/public/modules/tags/instance/instanceTagsController.js
@@ -0,0 +1,40 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+'use strict';
+
+angular.module('dgc.tags.instance').controller('InstanceTagController', ['$scope', 'DetailsResource', '$stateParams', '$state',
+    function($scope, DetailsResource, $stateParams, $state) {
+        $scope.id = $stateParams.id;
+
+        function getResourceData() {
+            DetailsResource.get({
+                id: $stateParams.id
+            }, function(data) {
+                $scope.traitsList = data.traitNames;
+            });
+        }
+        $scope.openAddTag = function() {
+            $state.go('addTag', {
+                id: $scope.id
+            });
+        };
+        getResourceData();
+        $scope.$on('refreshResourceData', getResourceData);
+    }
+]);

http://git-wip-us.apache.org/repos/asf/incubator-atlas/blob/4f61fff2/dashboard/public/modules/tags/instance/instanceTagsModule.js
----------------------------------------------------------------------
diff --git a/dashboard/public/modules/tags/instance/instanceTagsModule.js b/dashboard/public/modules/tags/instance/instanceTagsModule.js
new file mode 100644
index 0000000..5f7083d
--- /dev/null
+++ b/dashboard/public/modules/tags/instance/instanceTagsModule.js
@@ -0,0 +1,21 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+'use strict';
+
+angular.module('dgc.tags.instance', []);

http://git-wip-us.apache.org/repos/asf/incubator-atlas/blob/4f61fff2/dashboard/public/modules/tags/instance/views/createTag.html
----------------------------------------------------------------------
diff --git a/dashboard/public/modules/tags/instance/views/createTag.html b/dashboard/public/modules/tags/instance/views/createTag.html
new file mode 100644
index 0000000..f4db1ce
--- /dev/null
+++ b/dashboard/public/modules/tags/instance/views/createTag.html
@@ -0,0 +1,42 @@
+<div class="modal-header">
+	<h4 class="modal-title">Add tag</h4>
+</div>
+<div class="modal-body">
+	<div class="form-group">
+		<div align="center" class="error col-sm-12" ng-if="isError">
+			{{error}}
+		</div>
+	</div>
+	<form name="tagDefinitionform"  class="css-form" novalidate>
+		<div class="form-group hide">
+			<label for="category" class="col-sm-4 control-label">Category</label>
+			<div class="col-sm-8 input-spacing">
+				<select class="form-control" id="category" name="category"
+					ng-model="category" ng-change="categoryChange()" required>
+					<option value="{{key}}"
+						ng-repeat="(key, value) in categoryList"
+						ng-selected="{{key===category}}">{{key}}</option>
+				</select>
+			</div>
+		</div>
+		<div class="form-group" ng-class="{'has-error': (tagDefinitionform.tagDefinition.$invalid && tagDefinitionform.tagDefinition.$dirty)}">
+			<label class="control-label col-sm-4" for="tagDefinition">Tag definition</label>
+			<div class="col-sm-8 input-spacing">
+				<select ng-model="selectedType" class="form-control" id="tagDefinition" name="tagDefinition"
+					ng-change="getAttributeDefinations(); isError =false" required>
+					<option ng-repeat="data in typesList">{{data}}</option>
+				</select>
+			</div>
+		</div>
+		<div class="form-group" ng-repeat="(key, value) in propertiesList" ng-class="{'has-error': (tagDefinitionform.propertyId_{{$index}}.$invalid && tagDefinitionform.propertyId_{{$index}}.$dirty)}">
+			<label class="control-label col-sm-4" for="propertyId_{{$index}}">{{key}}</label>
+			<div class="col-sm-8 input-spacing">
+				<input type="text" class="form-control" id="propertyId_{{$index}}" name="propertyId_{{$index}}" ng-model="propertiesList[key]" ng-required="isRequired[key]"/>
+			</div>
+		</div>
+		<div class="modal-footer">
+			<button class="btn btn-success" type="submit" ng-click="ok(tagDefinitionform)" ng-disabled="tagDefinitionform.$invalid">Save</button>
+			<button class="btn btn-warning" type="button" ng-click="cancel()">Cancel</button>
+		</div>
+	</form>
+</div>

http://git-wip-us.apache.org/repos/asf/incubator-atlas/blob/4f61fff2/dashboard/public/modules/tags/instance/views/tags.html
----------------------------------------------------------------------
diff --git a/dashboard/public/modules/tags/instance/views/tags.html b/dashboard/public/modules/tags/instance/views/tags.html
new file mode 100644
index 0000000..33904b0
--- /dev/null
+++ b/dashboard/public/modules/tags/instance/views/tags.html
@@ -0,0 +1,28 @@
+<!--
+  ~ Licensed to the Apache Software Foundation (ASF) under one
+  ~ or more contributor license agreements.  See the NOTICE file
+  ~ distributed with this work for additional information
+  ~ regarding copyright ownership.  The ASF licenses this file
+  ~ to you under the Apache License, Version 2.0 (the
+  ~ "License"); you may not use this file except in compliance
+  ~ with the License.  You may obtain a copy of the License at
+  ~
+  ~     http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+  -->
+<div data-ng-controller="InstanceTagController">
+	<div class="container tag-list">
+		<h4>Tags</h4>
+		<ul>
+			<li ng-repeat="trait in traitsList" class="list-group-item">
+				{{trait}},</li>
+			<li class="list-group-item"><a ng-click="openAddTag()" href=""
+				class="add-tag">Add tag</a></li>
+		</ul>
+	</div>
+</div>
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-atlas/blob/4f61fff2/dashboard/public/modules/tags/tagAttributeDefinition.js
----------------------------------------------------------------------
diff --git a/dashboard/public/modules/tags/tagAttributeDefinition.js b/dashboard/public/modules/tags/tagAttributeDefinition.js
deleted file mode 100644
index 6b57bd1..0000000
--- a/dashboard/public/modules/tags/tagAttributeDefinition.js
+++ /dev/null
@@ -1,33 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * 'License'); you may not use this file except in compliance
- * with the License.  You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an 'AS IS' BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-'use strict';
-
-angular.module('dgc.tags').service('AttributeDefinition', function Attribute() {
-    this.getModel = function getJson() {
-        return {
-            name: null,
-            dataTypeName: 'string',
-            multiplicity: 'optional',
-            isComposite: false,
-            isUnique: false,
-            isIndexable: true,
-            reverseAttributeName: null
-        };
-    };
-});

http://git-wip-us.apache.org/repos/asf/incubator-atlas/blob/4f61fff2/dashboard/public/modules/tags/tagClasses.js
----------------------------------------------------------------------
diff --git a/dashboard/public/modules/tags/tagClasses.js b/dashboard/public/modules/tags/tagClasses.js
index 81ad77c..416acaa 100644
--- a/dashboard/public/modules/tags/tagClasses.js
+++ b/dashboard/public/modules/tags/tagClasses.js
@@ -35,6 +35,13 @@ angular.module('dgc.tags').factory('TagClasses', ['lodash', function ClassFactor
         CLASS: 'org.apache.atlas.typesystem.types.ClassType'
     };
 
+    var instanceRespons = {
+        ENUM: 'enumTypes',
+        STRUCT: 'structTypes',
+        TRAIT: 'traitTypes',
+        SUPER: 'superTypes'
+    };
+
     function Class(classId, className) {
         this.tags = [];
         this.id = classId;
@@ -65,6 +72,10 @@ angular.module('dgc.tags').factory('TagClasses', ['lodash', function ClassFactor
             output[classTypeKey] = this.tags;
             return output;
         };
+
+        this.instanceInfo = function() {
+            return instanceRespons[classId];
+        };
     }
 
     return _.chain(classes)

http://git-wip-us.apache.org/repos/asf/incubator-atlas/blob/4f61fff2/dashboard/public/modules/tags/tagsController.js
----------------------------------------------------------------------
diff --git a/dashboard/public/modules/tags/tagsController.js b/dashboard/public/modules/tags/tagsController.js
deleted file mode 100755
index e548287..0000000
--- a/dashboard/public/modules/tags/tagsController.js
+++ /dev/null
@@ -1,63 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License.  You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-'use strict';
-
-angular.module('dgc.tags').controller('TagsController', ['$scope', '$resource', '$state', '$stateParams', 'lodash', 'AttributeDefinition', 'TagClasses', 'TagsResource', 'NotificationService',
-    function($scope, $resource, $state, $stateParams, _, AttributeDefinition, Categories, TagsResource, NotificationService) {
-        $scope.categoryList = Categories;
-        $scope.category = 'TRAIT';
-        $scope.tagModel = {
-            typeName: null,
-            attributeDefinitions: []
-        };
-
-        $scope.addAttribute = function AddAttribute() {
-            $scope.tagModel.attributeDefinitions.push(AttributeDefinition.getModel());
-        };
-
-        $scope.categoryChange = function CategorySwitched() {
-            $scope.categoryInst = Categories[$scope.category].clearTags();
-        };
-
-        $scope.save = function saveTag(form) {
-            $scope.savedTag = null;
-            if (form.$valid) {
-                $scope.categoryInst = Categories[$scope.category];
-                $scope.categoryInst.clearTags().addTag($scope.tagModel);
-
-                NotificationService.reset();
-                $scope.saving = true;
-
-                TagsResource.save($scope.categoryInst.toJson()).$promise
-                    .then(function TagCreateSuccess() {
-                        NotificationService.info('"' + $scope.tagModel.typeName + '" has been created', false);
-                        return TagsResource.get({
-                            id: $scope.tagModel.typeName
-                        }).$promise;
-                    }).then(function TagFound(res) {
-                        $scope.savedTag = JSON.parse(res.definition);
-                    }).catch(function TagCreateFailed(error) {
-                        NotificationService.error(error.data.error, false);
-                    }).finally(function() {
-                        $scope.saving = false;
-                    });
-            }
-        };
-    }
-]);

http://git-wip-us.apache.org/repos/asf/incubator-atlas/blob/4f61fff2/dashboard/public/modules/tags/tagsRoutes.js
----------------------------------------------------------------------
diff --git a/dashboard/public/modules/tags/tagsRoutes.js b/dashboard/public/modules/tags/tagsRoutes.js
index a15c3ba..5d768a5 100755
--- a/dashboard/public/modules/tags/tagsRoutes.js
+++ b/dashboard/public/modules/tags/tagsRoutes.js
@@ -22,7 +22,24 @@ angular.module('dgc.tags').config(['$stateProvider',
     function($stateProvider) {
         $stateProvider.state('tags', {
             url: '/tags',
-            templateUrl: '/modules/tags/views/add.html'
+            templateUrl: '/modules/tags/definition/views/add.html'
+        });
+        $stateProvider.state('addTag', {
+            parent: 'details',
+            onEnter: ['$stateParams', '$state', '$modal', 'NavigationResource', function($stateParams, $state, $modal, NavigationResource) {
+                $modal.open({
+                    templateUrl: '/modules/tags/instance/views/createTag.html',
+                    controller: 'CreateTagController',
+                    windowClass: 'create-tag-entity',
+                    resolve: {
+                        typesList: function() {
+                            return NavigationResource.get().$promise;
+                        }
+                    }
+                }).result.finally(function() {
+                    $state.go('^');
+                });
+            }]
         });
     }
 ]);

http://git-wip-us.apache.org/repos/asf/incubator-atlas/blob/4f61fff2/dashboard/public/modules/tags/views/add.html
----------------------------------------------------------------------
diff --git a/dashboard/public/modules/tags/views/add.html b/dashboard/public/modules/tags/views/add.html
deleted file mode 100755
index 05ddd89..0000000
--- a/dashboard/public/modules/tags/views/add.html
+++ /dev/null
@@ -1,134 +0,0 @@
-<!--
-  ~ Licensed to the Apache Software Foundation (ASF) under one
-  ~ or more contributor license agreements.  See the NOTICE file
-  ~ distributed with this work for additional information
-  ~ regarding copyright ownership.  The ASF licenses this file
-  ~ to you under the Apache License, Version 2.0 (the
-  ~ "License"); you may not use this file except in compliance
-  ~ with the License.  You may obtain a copy of the License at
-  ~
-  ~     http://www.apache.org/licenses/LICENSE-2.0
-  ~
-  ~ Unless required by applicable law or agreed to in writing, software
-  ~ distributed under the License is distributed on an "AS IS" BASIS,
-  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-  ~ See the License for the specific language governing permissions and
-  ~ limitations under the License.
-  -->
-<div class="container">
-    <div class="appForm" data-ng-controller="TagsController">
-        <h4>Tag Definition</h4>
-
-        <form data-name="tagForm" class="form-horizontal" novalidate role="form">
-            <fieldset data-ng-disabled="saving">
-
-                <div class="form-group hide">
-                    <label for="category" class="col-sm-2 control-label">Category</label>
-
-                    <div class="col-sm-10">
-                        <select class="form-control" id="category" name="category" data-ng-model="category" data-ng-change="categoryChange()" required>
-                            <option value="{{key}}" data-ng-repeat="(key, value) in categoryList" ng-selected="{{key===category}}">{{key}}</option>
-                        </select>
-                    </div>
-                </div>
-                <div class="form-group" data-ng-class="{'has-error': tagForm.typeName.$invalid && tagForm.typeName.$dirty}">
-                    <label for="typeName" class="col-sm-2 control-label">Tag Name</label>
-
-                    <div class="col-sm-10">
-                        <input type="text" class="form-control" name="typeName" id="typeName" placeholder="Tag Name" data-ng-model="tagModel.typeName" required/>
-                    </div>
-                </div>
-                <ng-form name="attributeForm">
-                    <div class="form-group" data-ng-class="{'has-error': attributeForm.name.$invalid && attributeForm.name.$dirty}"
-                         data-ng-repeat-start="attribute in tagModel.attributeDefinitions">
-                        <label for="attributeId_{{$index}}" class="col-sm-2 control-label">Attribute name</label>
-
-                        <div class="col-sm-10">
-                          <!--   <div class="input-group"> -->
-                                <input type="text" class="form-control" name="name" id="attributeId_{{$index}}" placeholder="Attribute name" data-ng-model="attribute.name"
-                                       required/>
-                             <!--    <i class="input-group-addon fa fa-2x" data-ng-class="{'fa-angle-double-down':!attribute.$$show, 'fa-angle-double-up':attribute.$$show}"
-                                   data-ng-click="attribute.$$show=!attribute.$$show"></i> -->
-                           <!--  </div> -->
-                        </div>
-                    </div>
-                    <div class="form-group" data-ng-class="{'has-error': attributeForm.name.$invalid && attributeForm.name.$dirty}" data-ng-show="attribute.$$show">
-                        <label for="attributeDatatype_{{$index}}" class="col-sm-2 control-label">Data Type Name</label>
-
-                        <div class="col-sm-10">
-                            <input type="text" class="form-control" name="name" id="attributeDatatype_{{$index}}" placeholder="dataTypeName"
-                                   data-ng-model="attribute.dataTypeName"/>
-                        </div>
-                    </div>
-                    <div class="form-group" data-ng-class="{'has-error': attributeForm.name.$invalid && attributeForm.name.$dirty}" data-ng-show="attribute.$$show">
-                        <label for="attributeMultiplicity_{{$index}}" class="col-sm-2 control-label">Multiplicity</label>
-
-                        <div class="col-sm-10">
-                            <input type="text" class="form-control" name="name" id="attributeMultiplicity_{{$index}}" placeholder="multiplicity"
-                                   data-ng-model="attribute.multiplicity"/>
-                        </div>
-                    </div>
-
-                    <div class="form-group" data-ng-class="{'has-error': attributeForm.name.$invalid && attributeForm.name.$dirty}" data-ng-show="attribute.$$show">
-                        <label for="attributeIscomposite_{{$index}}" class="col-sm-2 control-label">isComposite</label>
-
-                        <div class="col-sm-10">
-                            <span class ="btnToggle">
-                            <a class="btn-sm " ng-class="{true: 'btn-primary'}[attribute.isComposite]" ng-click="attribute.isComposite = true">true </a>
-                            <a class="btn-sm " ng-class="{false: 'btn-danger'}[attribute.isComposite]" ng-click="attribute.isComposite = false"> false </a>
-
-                                </span>
-                        </div>
-                    </div>
-                    <div class="form-group" data-ng-class="{'has-error': attributeForm.name.$invalid && attributeForm.name.$dirty}" data-ng-show="attribute.$$show">
-                        <label for="attributeIsunique_{{$index}}" class="col-sm-2 control-label">isUnique</label>
-
-                        <div class="col-sm-10">
-                            <span class ="btnToggle">
-                            <a class="btn-sm " ng-class="{true: 'btn-primary'}[attribute.isUnique]" ng-click="attribute.isUnique = true">true </a>
-                            <a class="btn-sm " ng-class="{false: 'btn-danger'}[attribute.isUnique]" ng-click="attribute.isUnique = false"> false </a>
-
-                                </span>
-                        </div>
-                    </div>
-                    <div class="form-group" data-ng-class="{'has-error': attributeForm.name.$invalid && attributeForm.name.$dirty}" data-ng-show="attribute.$$show">
-                        <label for="attributeIndexable_{{$index}}" class="col-sm-2 control-label">isIndexable</label>
-
-                        <div class="col-sm-10">
-                            <span class ="btnToggle">
-                            <a class="btn-sm " ng-class="{true: 'btn-primary'}[attribute.isIndexable]" ng-click="attribute.isIndexable = true">true </a>
-                            <a class="btn-sm " ng-class="{false: 'btn-danger'}[attribute.isIndexable]" ng-click="attribute.isIndexable = false"> false </a>
-
-                                </span>
-                        </div>
-                    </div>
-
-
-                    <div class="form-group" data-ng-class="{'has-error': attributeForm.name.$invalid && attributeForm.name.$dirty}" data-ng-show="attribute.$$show"
-                         data-ng-repeat-end>
-                        <label for="attributeReverseName_{{$index}}" class="col-sm-2 control-label">reverseAttributeName</label>
-
-                        <div class="col-sm-10">
-                            <input type="text" class="form-control" name="reverseName" id="attributeReverseName_{{$index}}" placeholder="reverseAttributeName"
-                                   data-ng-model="attribute.reverseAttributeName"/>
-                        </div>
-                    </div>
-                </ng-form>
-                <div class="form-group text-right">
-                    <div class="col-sm-offset-2 col-sm-10">
-
-                        <button data-ng-click="addAttribute()" class="btn btn-default">Add Attribute</button>
-                    </div>
-                </div>
-                <div class="form-group">
-                    <div class="col-sm-offset-2 col-sm-10">
-                        <button type="submit" data-ng-click="save(tagForm)" data-ng-disabled="tagForm.$invalid" class="btn btn-default">Save</button>
-                    </div>
-                </div>
-            </fieldset>
-        </form>
-        <div class="row" data-ng-show="savedTag">
-            <pre>{{savedTag | json}}</pre>
-        </div>
-    </div>
-</div>
\ No newline at end of file


Mime
View raw message