ATLAS-2562: UI for Glossary

Signed-off-by: Madhan Neethiraj <[email protected]>


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

Branch: refs/heads/master
Commit: 3709842a0711b9aef51c0c6c6727015c63379931
Parents: 4ba39dc
Author: kevalbhatt <[email protected]>
Authored: Tue Apr 17 01:56:57 2018 +0530
Committer: Madhan Neethiraj <[email protected]>
Committed: Mon Apr 16 14:18:42 2018 -0700

----------------------------------------------------------------------
 dashboardv2/gruntfile.js                        |  56 +-
 dashboardv2/package.json                        |   3 +
 dashboardv2/public/css/scss/glossary.scss       |  53 ++
 dashboardv2/public/css/scss/search.scss         |   7 +-
 dashboardv2/public/css/scss/style.scss          |   1 +
 dashboardv2/public/index.html.tpl               |   2 +
 .../public/js/collection/VGlossaryList.js       |  72 +++
 dashboardv2/public/js/collection/VSearchList.js |   4 +-
 dashboardv2/public/js/main.js                   |  14 +-
 dashboardv2/public/js/models/VGlossary.js       | 111 ++++
 dashboardv2/public/js/router/Router.js          |  41 +-
 .../detail_page/DetailPageLayoutView_tmpl.html  |   8 +
 .../glossary/AssignTermLayoutViewTmpl.html      |  17 +
 .../CreateEditCategoryTermLayoutView_tmpl.html  |  36 ++
 .../CreateEditGlossaryLayoutView_tmpl.html      |  36 ++
 .../glossary/GlossaryDetailLayoutView_tmpl.html |  67 +++
 .../glossary/GlossaryLayoutView_tmpl.html       |  52 ++
 .../search/SearchResultLayoutView_tmpl.html     |   2 +
 .../templates/site/SideNavLayoutView_tmpl.html  |  10 +-
 .../public/js/utils/CommonViewFunction.js       | 217 +++++++-
 dashboardv2/public/js/utils/Globals.js          |   3 +-
 dashboardv2/public/js/utils/Messages.js         |   6 +
 dashboardv2/public/js/utils/UrlLinks.js         |  45 ++
 dashboardv2/public/js/utils/Utils.js            |   5 +
 .../views/detail_page/DetailPageLayoutView.js   |  73 ++-
 .../js/views/glossary/AssignTermLayoutView.js   | 151 ++++++
 .../CreateEditCategoryTermLayoutView.js         |  70 +++
 .../glossary/CreateEditGlossaryLayoutView.js    |  69 +++
 .../views/glossary/GlossaryDetailLayoutView.js  | 294 +++++++++++
 .../js/views/glossary/GlossaryLayoutView.js     | 528 +++++++++++++++++++
 .../public/js/views/schema/SchemaLayoutView.js  |   4 +-
 .../js/views/search/SearchResultLayoutView.js   | 108 +++-
 dashboardv2/public/js/views/site/Header.js      |   8 +-
 .../public/js/views/site/SideNavLayoutView.js   |  54 +-
 34 files changed, 2151 insertions(+), 76 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/atlas/blob/3709842a/dashboardv2/gruntfile.js
----------------------------------------------------------------------
diff --git a/dashboardv2/gruntfile.js b/dashboardv2/gruntfile.js
index fc8fa0d..2bcecfe 100644
--- a/dashboardv2/gruntfile.js
+++ b/dashboardv2/gruntfile.js
@@ -98,14 +98,15 @@ module.exports = function(grunt) {
                     'select2.full.min.js': { 'select2/dist/js': 'select2' },
                     'backgrid-select-all.min.js': { 'backgrid-select-all': 
'backgrid-select-all' },
                     'moment.min.js': { 'moment/min': 'moment/js' },
-                    'moment-timezone-with-data.min.js' : 
{'moment-timezone/builds' : 'moment-timezone'},
+                    'moment-timezone-with-data.min.js': { 
'moment-timezone/builds': 'moment-timezone' },
                     'jquery.placeholder.js': { 'jquery-placeholder': 
'jquery-placeholder/js' },
                     'platform.js': { 'platform': 'platform' },
                     'query-builder.standalone.min.js': { 
'jQuery-QueryBuilder/dist/js': 'jQueryQueryBuilder/js' },
                     'daterangepicker.js': { 'bootstrap-daterangepicker': 
'bootstrap-daterangepicker/js' },
                     'nv.d3.min.js': { 'nvd3/build': 'nvd3' },
                     'jquery.sparkline.min.js': { 'jquery-sparkline': 
'sparkline' },
-                    'table-dragger.js': { 'table-dragger/dist': 
'table-dragger' }
+                    'table-dragger.js': { 'table-dragger/dist': 
'table-dragger' },
+                    'jstree.min.js': { 'jstree/dist': 'jstree' }
                 }
 
             },
@@ -127,16 +128,22 @@ module.exports = function(grunt) {
                     'select2.min.css': { 'select2/dist/css': 'select2/css' },
                     'backgrid-select-all.min.css': { 'backgrid-select-all': 
'backgrid-select-all' },
                     'font-awesome.min.css': { 'font-awesome/css': 
'font-awesome/css' },
-                    '*': {
+                    '*': [{
                         'expand': true,
                         'dot': true,
                         'cwd': nodeModulePath + 'font-awesome',
                         'src': ['fonts/*.*'],
                         'dest': libPath + 'font-awesome/'
-                    },
+                    }, {
+                        'expand': true,
+                        'dot': true,
+                        'cwd': nodeModulePath + 'jstree/dist/themes/',
+                        'src': ['**'],
+                        'dest': libPath + 'jstree/css/'
+                    }],
                     'query-builder.default.min.css': { 
'jQuery-QueryBuilder/dist/css': 'jQueryQueryBuilder/css' },
                     'daterangepicker.css': { 'bootstrap-daterangepicker': 
'bootstrap-daterangepicker/css' },
-                    'nv.d3.min.css': { 'nvd3/build': 'nvd3/css' }
+                    'nv.d3.min.css': { 'nvd3/build': 'nvd3/css' },
                 }
 
             },
@@ -160,7 +167,7 @@ module.exports = function(grunt) {
                         { 'dagre-d3': 'dagre-d3' },
                         { 'platform': 'platform/' },
                         { 'jQuery-QueryBuilder': 'jQueryQueryBuilder/' },
-                        {'moment-timezone' : 'moment-timezone'}
+                        { 'moment-timezone': 'moment-timezone' }
                     ],
                     'LICENSE.md': [{ 'backbone.babysitter': 
'backbone-babysitter' },
                         { 'backbone.wreqr': 'backbone-wreqr' },
@@ -179,6 +186,14 @@ module.exports = function(grunt) {
                 }
             }
         },
+        rename: {
+            main: {
+                files: [
+                    { src: [libPath + '/jstree/css/default/style.min.css'], 
dest: libPath + '/jstree/css/default/default-theme.min.css' },
+                    { src: [libPath + 
'/jstree/css/default-dark/style.min.css'], dest: libPath + 
'/jstree/css/default-dark/default-dark-theme.min.css' },
+                ]
+            }
+        },
         sass: {
             dist: {
                 files: {
@@ -296,8 +311,12 @@ module.exports = function(grunt) {
                     });
                 }
             } else {
-                key = Object.keys(obj);
-                options.libFiles.push({ 'src': pathPrefix.srcPrefix + key + 
"/" + fileName, 'dest': pathPrefix.destPrefix + obj[key] + "/" + fileName });
+                if (fileName == "*") {
+                    options.libFiles.push(obj);
+                } else {
+                    key = Object.keys(obj);
+                    options.libFiles.push({ 'src': pathPrefix.srcPrefix + key 
+ "/" + fileName, 'dest': pathPrefix.destPrefix + obj[key] + "/" + fileName });
+                }
             }
         };
 
@@ -305,16 +324,12 @@ module.exports = function(grunt) {
         var options = npmCopy[key].options,
             files = npmCopy[key].files;
         for (var fileName in files) {
-            if (fileName == "*") {
-                libFiles.push(files[fileName]);
-            } else {
-                createPath({
-                    'obj': files[fileName],
-                    'libFiles': libFiles,
-                    'pathPrefix': options,
-                    'fileName': fileName
-                });
-            }
+            createPath({
+                'obj': files[fileName],
+                'libFiles': libFiles,
+                'pathPrefix': options,
+                'fileName': fileName
+            });
         }
     };
     grunt.config.set('copy.libs', { files: libFiles });
@@ -326,6 +341,7 @@ module.exports = function(grunt) {
     grunt.loadNpmTasks('grunt-contrib-cssmin');
     grunt.loadNpmTasks('grunt-contrib-htmlmin');
     grunt.loadNpmTasks('grunt-template');
+    grunt.loadNpmTasks('grunt-contrib-rename');
 
     require('load-grunt-tasks')(grunt);
 
@@ -333,6 +349,7 @@ module.exports = function(grunt) {
         'clean',
         'copy:libs',
         'copy:dist',
+        'rename',
         'sass:dist',
         'template',
         'setupProxies:server',
@@ -344,6 +361,7 @@ module.exports = function(grunt) {
         'clean',
         'copy:libs',
         'copy:build',
+        'rename',
         'sass:build',
         'template'
     ]);
@@ -352,6 +370,7 @@ module.exports = function(grunt) {
         'clean',
         'copy:libs',
         'copy:dist',
+        'rename',
         'sass:dist',
         'uglify',
         'cssmin',
@@ -365,6 +384,7 @@ module.exports = function(grunt) {
         'clean',
         'copy:libs',
         'copy:build',
+        'rename',
         'sass:build',
         'uglify',
         'cssmin',

http://git-wip-us.apache.org/repos/asf/atlas/blob/3709842a/dashboardv2/package.json
----------------------------------------------------------------------
diff --git a/dashboardv2/package.json b/dashboardv2/package.json
index 1f28c4b..e543468 100644
--- a/dashboardv2/package.json
+++ b/dashboardv2/package.json
@@ -37,8 +37,10 @@
     "jquery-asBreadcrumbs": "0.2.2",
     "jquery-placeholder": "2.3.1",
     "jquery-sparkline": "2.4.0",
+    "jstree": "^3.3.5",
     "moment": "2.21.0",
     "moment-timezone": "0.5.14",
+    "npm": "^5.8.0",
     "nvd3": "1.8.5",
     "platform": "1.3.4",
     "pnotify": "3.2.0",
@@ -56,6 +58,7 @@
     "grunt-contrib-copy": "1.0.0",
     "grunt-contrib-cssmin": "2.0.0",
     "grunt-contrib-htmlmin": "2.2.0",
+    "grunt-contrib-rename": "^0.2.0",
     "grunt-contrib-uglify": "2.1.0",
     "grunt-contrib-watch": "1.0.0",
     "grunt-middleware-proxy": "1.0.7",

http://git-wip-us.apache.org/repos/asf/atlas/blob/3709842a/dashboardv2/public/css/scss/glossary.scss
----------------------------------------------------------------------
diff --git a/dashboardv2/public/css/scss/glossary.scss 
b/dashboardv2/public/css/scss/glossary.scss
new file mode 100644
index 0000000..54210c0
--- /dev/null
+++ b/dashboardv2/public/css/scss/glossary.scss
@@ -0,0 +1,53 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+.jstree-contextmenu {
+    z-index: 99;
+}
+
+.jstree-default-dark {
+    background: transparent !important;
+    .jstree-clicked,
+    .jstree-wholerow-clicked {
+        background: $color_jungle_green_approx !important;
+    }
+    .jstree-hovered {
+        background: $color_star_dust_approx;
+    }
+    .jstree-anchor {
+        color: #dbdbdb;
+    }
+    .jstree-search {
+        color: #fbfece !important
+    }
+    li[role="treeitem"] {
+        .jstree-wholerow-clicked {
+            .tools {
+                display: inline-block;
+            }
+        }
+        .tools {
+            display: none;
+            position: relative;
+            width: 9%;
+            float: right;
+            text-align: center;
+            cursor: pointer;
+        }
+    }
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/atlas/blob/3709842a/dashboardv2/public/css/scss/search.scss
----------------------------------------------------------------------
diff --git a/dashboardv2/public/css/scss/search.scss 
b/dashboardv2/public/css/scss/search.scss
index 9500558..0f9cb1c 100644
--- a/dashboardv2/public/css/scss/search.scss
+++ b/dashboardv2/public/css/scss/search.scss
@@ -94,11 +94,11 @@ $color_celeste_approx: #1D1F2B;
     }
 }
 
-.popup-tag {
+.popup-tag-term {
     display: none;
 }
 
-.popover-tag {
+.popover-tag-term {
     .btn {
         display: block;
     }
@@ -112,7 +112,8 @@ $color_celeste_approx: #1D1F2B;
         }
     }
 }
-.table-responsive{
+
+.table-responsive {
     position: relative;
 }
 

http://git-wip-us.apache.org/repos/asf/atlas/blob/3709842a/dashboardv2/public/css/scss/style.scss
----------------------------------------------------------------------
diff --git a/dashboardv2/public/css/scss/style.scss 
b/dashboardv2/public/css/scss/style.scss
index ee33f48..2b226cd 100644
--- a/dashboardv2/public/css/scss/style.scss
+++ b/dashboardv2/public/css/scss/style.scss
@@ -31,4 +31,5 @@
 @import "tag.scss";
 @import "search.scss";
 @import "profile-table.scss";
+@import "glossary.scss";
 @import "override.scss";
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/atlas/blob/3709842a/dashboardv2/public/index.html.tpl
----------------------------------------------------------------------
diff --git a/dashboardv2/public/index.html.tpl 
b/dashboardv2/public/index.html.tpl
index 553ca1b..8c67cb4 100644
--- a/dashboardv2/public/index.html.tpl
+++ b/dashboardv2/public/index.html.tpl
@@ -54,6 +54,8 @@
     <link 
href="js/libs/jQueryQueryBuilder/css/query-builder.default.min.css?bust=<%- 
bust %>" rel="stylesheet">
     <link 
href="js/libs/bootstrap-daterangepicker/css/daterangepicker.css?bust=<%- bust 
%>" rel="stylesheet">
     <link rel="stylesheet" href="js/libs/nvd3/css/nv.d3.min.css?bust=<%- bust 
%>">
+    <link 
href="js/libs/jstree/css/default-dark/default-dark-theme.min.css?bust=<%- bust 
%>" rel="stylesheet">
+    <link href="js/libs/jstree/css/default/default-theme.min.css?bust=<%- bust 
%>" rel="stylesheet">
     <link href="css/style.css?bust=<%- bust %>" rel="stylesheet">
 </head>
 

http://git-wip-us.apache.org/repos/asf/atlas/blob/3709842a/dashboardv2/public/js/collection/VGlossaryList.js
----------------------------------------------------------------------
diff --git a/dashboardv2/public/js/collection/VGlossaryList.js 
b/dashboardv2/public/js/collection/VGlossaryList.js
new file mode 100644
index 0000000..9c4918f
--- /dev/null
+++ b/dashboardv2/public/js/collection/VGlossaryList.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.
+ */
+
+define(['require',
+    'utils/Globals',
+    'collection/BaseCollection',
+    'models/VGlossary',
+    'utils/UrlLinks'
+], function(require, Globals, BaseCollection, VGlossary, UrlLinks) {
+    'use strict';
+    var VGlossaryList = BaseCollection.extend(
+        //Prototypal attributes
+        {
+            url: UrlLinks.glossaryApiUrl(),
+
+            model: VGlossary,
+
+            initialize: function() {
+                this.modelName = 'VGlossary';
+                this.modelAttrName = '';
+            },
+            parseRecords: function(resp, options) {
+                if (_.isEmpty(this.modelAttrName)) {
+                    return resp;
+                } else {
+                    return resp[this.modelAttrName]
+                }
+            },
+            getCategory: function(options) {
+                var url = UrlLinks.categoryApiUrl({ "guid": options.guid, 
"related": options.related }),
+                    apiOptions = _.extend({
+                        contentType: 'application/json',
+                        dataType: 'json'
+                    }, options.ajaxOptions);
+                return this.constructor.nonCrudOperation.call(this, url, 
'GET', apiOptions);
+            },
+            getTerm: function(options) {
+                var url = UrlLinks.termApiUrl({ "guid": options.guid, 
"related": options.related }),
+                    apiOptions = _.extend({
+                        contentType: 'application/json',
+                        dataType: 'json'
+                    }, options.ajaxOptions);
+                return this.constructor.nonCrudOperation.call(this, url, 
'GET', apiOptions);
+            }
+        },
+        //Static Class Members
+        {
+            /**
+             * Table Cols to be passed to Backgrid
+             * UI has to use this as base and extend this.
+             *
+             */
+            tableCols: {}
+        }
+    );
+    return VGlossaryList;
+});
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/atlas/blob/3709842a/dashboardv2/public/js/collection/VSearchList.js
----------------------------------------------------------------------
diff --git a/dashboardv2/public/js/collection/VSearchList.js 
b/dashboardv2/public/js/collection/VSearchList.js
index 28c246f..db380f6 100644
--- a/dashboardv2/public/js/collection/VSearchList.js
+++ b/dashboardv2/public/js/collection/VSearchList.js
@@ -53,9 +53,11 @@ define(['require',
                         entities.push(temp);
                     });
                     return entities;
-                } else {
+                } else if (resp.entities) {
                     this.dynamicTable = false;
                     return resp.entities ? resp.entities : [];
+                } else {
+                    return resp ? resp : [];
                 }
             },
             getBasicRearchResult: function(options) {

http://git-wip-us.apache.org/repos/asf/atlas/blob/3709842a/dashboardv2/public/js/main.js
----------------------------------------------------------------------
diff --git a/dashboardv2/public/js/main.js b/dashboardv2/public/js/main.js
index a0e4bc5..6c72cca 100644
--- a/dashboardv2/public/js/main.js
+++ b/dashboardv2/public/js/main.js
@@ -114,11 +114,11 @@ require.config({
         'daterangepicker': {
             'deps': ['jquery', 'moment']
         },
-        'moment-timezone' : {
-            'deps' : ['moment']
+        'moment-timezone': {
+            'deps': ['moment']
         },
-        'moment':{
-            'exports':['moment']
+        'moment': {
+            'exports': ['moment']
         },
         'nvd3': {
             'deps': ['d3']
@@ -126,6 +126,9 @@ require.config({
         'sparkline': {
             'deps': ['jquery'],
             'exports': ['sparkline']
+        },
+        'jstree': {
+            'deps': ['jquery']
         }
     },
 
@@ -167,7 +170,8 @@ require.config({
         'daterangepicker': 'libs/bootstrap-daterangepicker/js/daterangepicker',
         'nvd3': 'libs/nvd3/nv.d3.min',
         'sparkline': 'libs/sparkline/jquery.sparkline.min',
-        'table-dragger': 'libs/table-dragger/table-dragger'
+        'table-dragger': 'libs/table-dragger/table-dragger',
+        'jstree': 'libs/jstree/jstree.min'
     },
 
     /**

http://git-wip-us.apache.org/repos/asf/atlas/blob/3709842a/dashboardv2/public/js/models/VGlossary.js
----------------------------------------------------------------------
diff --git a/dashboardv2/public/js/models/VGlossary.js 
b/dashboardv2/public/js/models/VGlossary.js
new file mode 100644
index 0000000..63eb9d2
--- /dev/null
+++ b/dashboardv2/public/js/models/VGlossary.js
@@ -0,0 +1,111 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+define(['require',
+    'utils/Globals',
+    'models/BaseModel',
+    'utils/UrlLinks'
+], function(require, Globals, VBaseModel, UrlLinks) {
+    'use strict';
+    var VGlossary = VBaseModel.extend({
+
+        urlRoot: UrlLinks.glossaryApiUrl(),
+
+        defaults: {},
+
+        serverSchema: {},
+
+        idAttribute: 'guid',
+
+        initialize: function() {
+            this.modelName = 'VGlossary';
+        },
+        toString: function() {
+            return this.get('name');
+        },
+        createEditCategory: function(options) {
+            var type = "POST",
+                url = UrlLinks.categoryApiUrl();
+            if (options.guid) {
+                type = "PUT";
+                url = UrlLinks.categoryApiUrl({ guid: options.guid });
+            }
+            options = _.extend({
+                contentType: 'application/json',
+                dataType: 'json'
+            }, options);
+            return this.constructor.nonCrudOperation.call(this, url, type, 
options);
+        },
+        createEditTerm: function(options) {
+            var type = "POST",
+                url = UrlLinks.termApiUrl();
+            if (options.guid) {
+                type = "PUT";
+                url = UrlLinks.termApiUrl({ guid: options.guid });
+            }
+            options = _.extend({
+                contentType: 'application/json',
+                dataType: 'json'
+            }, options);
+            return this.constructor.nonCrudOperation.call(this, url, type, 
options);
+        },
+        deleteCategory: function(guid, options) {
+            var url = UrlLinks.categoryApiUrl({ "guid": guid });
+            options = _.extend({
+                contentType: 'application/json',
+                dataType: 'json'
+            }, options);
+            return this.constructor.nonCrudOperation.call(this, url, 'DELETE', 
options);
+        },
+        deleteTerm: function(guid, options) {
+            var url = UrlLinks.termApiUrl({ "guid": guid });
+            options = _.extend({
+                contentType: 'application/json',
+                dataType: 'json'
+            }, options);
+            return this.constructor.nonCrudOperation.call(this, url, 'DELETE', 
options);
+        },
+        assignTermToEntity: function(guid, options) {
+            var url = UrlLinks.termToEntityApiUrl(guid);
+            options = _.extend({
+                contentType: 'application/json',
+                dataType: 'json'
+            }, options);
+            return this.constructor.nonCrudOperation.call(this, url, 'POST', 
options);
+        },
+        assignTermToCategory: function(options) {
+            return this.createEditCategory(options);
+        },
+        assignCategoryToTerm: function(options) {
+            return this.createEditTerm(options);
+        },
+        removeTermFromEntity: function(guid, options) {
+            var url = UrlLinks.termToEntityApiUrl(guid);
+            options = _.extend({
+                contentType: 'application/json',
+                dataType: 'json'
+            }, options);
+            return this.constructor.nonCrudOperation.call(this, url, 'DELETE', 
options);
+        },
+        removeTermFromCategory: function() {
+
+        },
+        removeCategoryFromTerm: function() {}
+    }, {});
+    return VGlossary;
+});
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/atlas/blob/3709842a/dashboardv2/public/js/router/Router.js
----------------------------------------------------------------------
diff --git a/dashboardv2/public/js/router/Router.js 
b/dashboardv2/public/js/router/Router.js
index 3d035ad..d4cdf26 100644
--- a/dashboardv2/public/js/router/Router.js
+++ b/dashboardv2/public/js/router/Router.js
@@ -24,8 +24,8 @@ define([
     'utils/Globals',
     'utils/Utils',
     'utils/UrlLinks',
-    'collection/VTagList'
-], function($, _, Backbone, App, Globals, Utils, UrlLinks, VTagList) {
+    'collection/VGlossaryList'
+], function($, _, Backbone, App, Globals, Utils, UrlLinks, VGlossaryList) {
     var AppRouter = Backbone.Router.extend({
         routes: {
             // Define some URL routes
@@ -36,6 +36,8 @@ define([
             '!/detailPage/:id': 'detailPage',
             '!/tag': 'commonAction',
             '!/search': 'commonAction',
+            '!/glossary': 'commonAction',
+            '!/glossary/:id': 'glossaryDetailPage',
             // Default
             '*actions': 'defaultAction'
         },
@@ -45,14 +47,19 @@ define([
             this.bindCommonEvents();
             this.listenTo(this, 'route', this.postRouteExecute, this);
             this.searchVent = new Backbone.Wreqr.EventAggregator();
+            this.glossaryCollection = new VGlossaryList([], {});
             this.preFetchedCollectionLists = {
                 'entityDefCollection': this.entityDefCollection,
                 'typeHeaders': this.typeHeaders,
                 'enumDefCollection': this.enumDefCollection,
-                'classificationDefCollection': this.classificationDefCollection
+                'classificationDefCollection': 
this.classificationDefCollection,
+                'glossaryCollection': this.glossaryCollection
             }
             this.sharedObj = {
                 searchTableColumns: {},
+                glossary: {
+                    selectedItem: {}
+                },
                 searchTableFilters: {
                     tagFilters: {},
                     entityFilters: {}
@@ -169,6 +176,31 @@ define([
                 }
             });
         },
+        glossaryDetailPage: function(id) {
+            var that = this;
+            if (id) {
+                require([
+                    'views/site/Header',
+                    'views/glossary/GlossaryDetailLayoutView',
+                    'views/site/SideNavLayoutView'
+                ], function(Header, GlossaryDetailLayoutView, 
SideNavLayoutView) {
+                    var paramObj = Utils.getUrlState.getQueryParams();
+                    App.rNHeader.show(new Header());
+                    if (!App.rSideNav.currentView) {
+                        App.rSideNav.show(new SideNavLayoutView(
+                            _.extend({}, that.preFetchedCollectionLists, 
that.sharedObj, { 'guid': id, 'value': paramObj })
+                        ));
+                    } else {
+                        
App.rSideNav.currentView.RGlossaryLayoutView.currentView.manualRender(_.extend({},
 { 'guid': id, 'value': paramObj }));
+                        App.rSideNav.currentView.selectTab();
+                    }
+                    App.rNContent.show(new GlossaryDetailLayoutView(_.extend({
+                        'guid': id,
+                        'value': paramObj
+                    }, that.preFetchedCollectionLists, that.sharedObj)));
+                });
+            }
+        },
         commonAction: function() {
             var that = this;
             require([
@@ -188,8 +220,11 @@ define([
                     App.rSideNav.currentView.selectTab();
                     if (Utils.getUrlState.isTagTab()) {
                         
App.rSideNav.currentView.RTagLayoutView.currentView.manualRender();
+                    } else if (Utils.getUrlState.isGlossaryTab()) {
+                        
App.rSideNav.currentView.RGlossaryLayoutView.currentView.manualRender(_.extend({},
 paramObj));
                     }
                 }
+
                 if (Globals.entityCreate && Utils.getUrlState.isSearchTab()) {
                     App.rNContent.show(new SearchDetailLayoutView(
                         _.extend({

http://git-wip-us.apache.org/repos/asf/atlas/blob/3709842a/dashboardv2/public/js/templates/detail_page/DetailPageLayoutView_tmpl.html
----------------------------------------------------------------------
diff --git 
a/dashboardv2/public/js/templates/detail_page/DetailPageLayoutView_tmpl.html 
b/dashboardv2/public/js/templates/detail_page/DetailPageLayoutView_tmpl.html
index a77ffc1..a23797f 100644
--- a/dashboardv2/public/js/templates/detail_page/DetailPageLayoutView_tmpl.html
+++ b/dashboardv2/public/js/templates/detail_page/DetailPageLayoutView_tmpl.html
@@ -30,6 +30,14 @@
                 </button>
             </div>
         </div>
+        <div class="form-group">
+            <span class="control-label-sm-pr pull-left">Term:</span>
+            <div class="pull-left" data-id="termList">
+                <button class="btn btn-action btn-sm" title="Add Term" 
data-id="addTerm">
+                    <i class="fa fa-plus"> </i>
+                </button>
+            </div>
+        </div>
         <div class="form-group" style="display: none;" 
data-id="propagatedTagDiv">
             <span class="control-label-sm-pr pull-left">Propagated 
Classifications:</span>
             <div class="pull-left" data-id="propagatedTagList">

http://git-wip-us.apache.org/repos/asf/atlas/blob/3709842a/dashboardv2/public/js/templates/glossary/AssignTermLayoutViewTmpl.html
----------------------------------------------------------------------
diff --git 
a/dashboardv2/public/js/templates/glossary/AssignTermLayoutViewTmpl.html 
b/dashboardv2/public/js/templates/glossary/AssignTermLayoutViewTmpl.html
new file mode 100644
index 0000000..1590a29
--- /dev/null
+++ b/dashboardv2/public/js/templates/glossary/AssignTermLayoutViewTmpl.html
@@ -0,0 +1,17 @@
+<!--
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+-->
+<div id="r_glossaryTree"></div>
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/atlas/blob/3709842a/dashboardv2/public/js/templates/glossary/CreateEditCategoryTermLayoutView_tmpl.html
----------------------------------------------------------------------
diff --git 
a/dashboardv2/public/js/templates/glossary/CreateEditCategoryTermLayoutView_tmpl.html
 
b/dashboardv2/public/js/templates/glossary/CreateEditCategoryTermLayoutView_tmpl.html
new file mode 100644
index 0000000..8f17f40
--- /dev/null
+++ 
b/dashboardv2/public/js/templates/glossary/CreateEditCategoryTermLayoutView_tmpl.html
@@ -0,0 +1,36 @@
+<!--
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+-->
+<form name="tagDefinitionform" class="form-horizontal" 
data-id="categoryTermForm">
+    <div class="form-group">
+        <label class="control-label col-sm-2 {{#if create}}required{{/if}}" 
for="name">Name</label>
+        <div class="col-sm-10">
+            <input class="form-control" data-id="displayName" 
name="displayName" value="{{modelJSON.displayName}}" 
placeholder="Name(required)" autofocus/>
+        </div>
+    </div>
+    <div class="form-group">
+        <label class="control-label col-sm-2" for="description">Short 
Description</label>
+        <div class="col-sm-10">
+            <input class="form-control" name="shortDescription" 
data-id="shortDescription" value="{{modelJSON.shortDescription}}" 
placeholder="Short Description" />
+        </div>
+    </div>
+    <div class="form-group">
+        <label class="control-label col-sm-2" for="description">Long 
Description</label>
+        <div class="col-sm-10">
+            <textarea class="form-control" name="longDescription" 
data-id="longDescription" placeholder="Long 
Description">{{modelJSON.longDescription}}</textarea>
+        </div>
+    </div>
+</form>
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/atlas/blob/3709842a/dashboardv2/public/js/templates/glossary/CreateEditGlossaryLayoutView_tmpl.html
----------------------------------------------------------------------
diff --git 
a/dashboardv2/public/js/templates/glossary/CreateEditGlossaryLayoutView_tmpl.html
 
b/dashboardv2/public/js/templates/glossary/CreateEditGlossaryLayoutView_tmpl.html
new file mode 100644
index 0000000..f783706
--- /dev/null
+++ 
b/dashboardv2/public/js/templates/glossary/CreateEditGlossaryLayoutView_tmpl.html
@@ -0,0 +1,36 @@
+<!--
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+-->
+<form name="tagDefinitionform" class="form-horizontal" data-id="glossaryForm">
+    <div class="form-group">
+        <label class="control-label col-sm-2 {{#if create}}required{{/if}}" 
for="name">Name</label>
+        <div class="col-sm-10">
+            <input class="form-control" name="displayName" 
value="{{displayName}}" data-id="displayName" placeholder="Display 
Name(required)" autofocus/>
+        </div>
+    </div>
+    <div class="form-group">
+        <label class="control-label col-sm-2" for="description">Short 
Description</label>
+        <div class="col-sm-10">
+            <input class="form-control" name="shortDescription" 
data-id="shortDescription" value="{{shortDescription}}" placeholder="Short 
Description" />
+        </div>
+    </div>
+    <div class="form-group">
+        <label class="control-label col-sm-2" for="description">Long 
Description</label>
+        <div class="col-sm-10">
+            <textarea class="form-control" name="longDescription" 
data-id="longDescription" placeholder="Long 
Description">{{longDescription}}</textarea>
+        </div>
+    </div>
+</form>
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/atlas/blob/3709842a/dashboardv2/public/js/templates/glossary/GlossaryDetailLayoutView_tmpl.html
----------------------------------------------------------------------
diff --git 
a/dashboardv2/public/js/templates/glossary/GlossaryDetailLayoutView_tmpl.html 
b/dashboardv2/public/js/templates/glossary/GlossaryDetailLayoutView_tmpl.html
new file mode 100644
index 0000000..25967ea
--- /dev/null
+++ 
b/dashboardv2/public/js/templates/glossary/GlossaryDetailLayoutView_tmpl.html
@@ -0,0 +1,67 @@
+<!--
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+-->
+<div class="page-title clearfix">
+    <div class="fontLoader">
+        <i class="fa fa-refresh fa-spin-custom"></i>
+    </div>
+    <div data-id="details" class="clearfix form-horizontal col-sm-12">
+        <h1 class="row title"><span data-id="title"></span></h1>
+        <button type="button" data-id="editButton" class="btn btn-sm 
btn-action pull-right"><i class="fa fa-pencil"></i></button>
+        <div class="form-group clearfix">
+            <span class="pull-left text-muted">Short Description:&nbsp;</span>
+            <div class="pull-left">
+                <p data-id="shortDescription"></p>
+            </div>
+        </div>
+        <div class="form-group clearfix">
+            <span class="pull-left text-muted">Long Description:&nbsp;</span>
+            <div class="pull-left">
+                <p data-id="longDescription"></p>
+            </div>
+        </div>
+        {{#if isTermView}}
+        <div class="form-group clearfix">
+            <span class="control-label-sm-pr pull-left">Categories:</span>
+            <div class="pull-left" data-id="categoryList">
+                <button class="btn btn-action btn-sm" title="Add Category" 
data-id="addCategory">
+                    <i class="fa fa-plus"> </i>
+                </button>
+            </div>
+        </div>
+        {{/if}} {{#if isCategoryView}}
+        <div class="form-group clearfix">
+            <span class="control-label-sm-pr pull-left">Term:</span>
+            <div class="pull-left" data-id="termList">
+                <button class="btn btn-action btn-sm" title="Add Term" 
data-id="addTerm">
+                    <i class="fa fa-plus"> </i>
+                </button>
+            </div>
+        </div>
+        {{/if}}
+    </div>
+</div>
+<div class="container-fluid gray-bg">
+    <div class="row">
+        <div class="col-sm-custom">
+            <div id="r_searchResultLayoutView">
+                <div class="fontLoader" style="display: block;min-height: 
50px;position:relative;margin-top: 25px;">
+                    <i class="fa fa-refresh fa-spin-custom"></i>
+                </div>
+            </div>
+        </div>
+    </div>
+</div>
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/atlas/blob/3709842a/dashboardv2/public/js/templates/glossary/GlossaryLayoutView_tmpl.html
----------------------------------------------------------------------
diff --git 
a/dashboardv2/public/js/templates/glossary/GlossaryLayoutView_tmpl.html 
b/dashboardv2/public/js/templates/glossary/GlossaryLayoutView_tmpl.html
new file mode 100644
index 0000000..f29f4e7
--- /dev/null
+++ b/dashboardv2/public/js/templates/glossary/GlossaryLayoutView_tmpl.html
@@ -0,0 +1,52 @@
+<!--
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+-->
+<div class="col-sm-12 add-seperator">
+    <div class="row">
+        {{#unless isAssignView}}
+        <div class="col-sm-8 no-padding" style="margin-top: 5px;">
+            <span class="pull-left">Terms</span>
+            <label class="switch pull-left">
+                <input type="checkbox" class="switch-input" 
name="glossaryView" value="text" />
+                <span class="switch-slider"></span>
+            </label>
+            <span class="pull-left">Category</span>
+        </div>
+        <div class="{{#if isAssignView}}col-sm-2{{else}}col-sm-4{{/if}} 
no-padding-right">
+            <button type="button" class="btn btn-action btn-md pull-right" 
title="Refresh" data-id="refreshGlossary" onclick="this.blur();" 
type="button"><i class="fa fa-refresh"></i></button>
+            <button type="button" class="btn btn-action btn-md pull-right" 
data-id="createGlossary" type="button"><i class="fa fa-plus"></i></button>
+            {{/unless}}
+        </div>
+    </div>
+</div>
+<div class="row">
+    <div class="col-sm-12">
+        <div class="no-padding col-sm-12 term-view">
+            <div>
+                <input type="text" class="form-control" data-id="searchTerm" 
placeholder="{{#if isAssignView}}Search Term{{else}}Search Glossary, 
Term{{/if}}">
+            </div>
+            <div data-id="termTree" style="margin-top: 5px;">
+            </div>
+        </div>
+        <div class="col-sm-12 no-padding category-view" style="display: none;">
+            <div>
+                <input type="text" class="form-control" 
data-id="searchCategory" placeholder="{{#if isAssignView}}Search 
Catalog{{else}}Search Glossary, Category{{/if}}">
+            </div>
+            <div data-id="categoryTree" style="margin-top: 5px;">
+            </div>
+        </div>
+    </div>
+</div>
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/atlas/blob/3709842a/dashboardv2/public/js/templates/search/SearchResultLayoutView_tmpl.html
----------------------------------------------------------------------
diff --git 
a/dashboardv2/public/js/templates/search/SearchResultLayoutView_tmpl.html 
b/dashboardv2/public/js/templates/search/SearchResultLayoutView_tmpl.html
index b7302cd..411aaab 100644
--- a/dashboardv2/public/js/templates/search/SearchResultLayoutView_tmpl.html
+++ b/dashboardv2/public/js/templates/search/SearchResultLayoutView_tmpl.html
@@ -36,11 +36,13 @@
                             id="historicalentities"/>
                             <b>Show historical entities</b></label>
                     </div>
+                    {{#ifCond fromView '!==' "glossary"}}
                     <div class="inline" data-id="containerCheckBox" 
style="display: none;">
                         <label class="checkbox-inline btn" 
for="subclassifications">
                             <input type="checkbox" 
data-id="checkSubClassification" data-value="excludeSC" 
id="subclassifications"/>
                             <b>Exclude sub-classifications</b></label>
                     </div>
+                    {{/ifCond}}
                     {{#ifCond fromView '!==' "classification"}}
                     <div class="inline" data-id="containerCheckBox" 
style="display: none;">
                         <label class="checkbox-inline btn" for="subtypes">

http://git-wip-us.apache.org/repos/asf/atlas/blob/3709842a/dashboardv2/public/js/templates/site/SideNavLayoutView_tmpl.html
----------------------------------------------------------------------
diff --git a/dashboardv2/public/js/templates/site/SideNavLayoutView_tmpl.html 
b/dashboardv2/public/js/templates/site/SideNavLayoutView_tmpl.html
index 942188e..31ac8e4 100644
--- a/dashboardv2/public/js/templates/site/SideNavLayoutView_tmpl.html
+++ b/dashboardv2/public/js/templates/site/SideNavLayoutView_tmpl.html
@@ -19,15 +19,19 @@
         <a href="{{apiBaseUrl}}/index.html"><i class="fa fa-globe"></i> Apache 
Atlas</a>
     </li>
     <ul class="tabs" style="width: 100%;" role="tablist">
-        <li role="presentation" class="{{tabClass}}"><a href="#tab-search" 
aria-controls="tab-search" data-name="tab-search" role="tab" data-toggle="tab" 
class=""><i class="fa fa-search"></i> Search</a></li>
-        <li role="presentation" class="{{tabClass}}"><a href="#tab-tag" 
aria-controls="tab-tag" data-name="tab-tag" role="tab" data-toggle="tab"><i 
class="fa fa-tags"></i> Classification</a></li>
+        <li role="presentation" class="tab col-sm-3"><a href="#tab-search" 
aria-controls="tab-search" data-name="tab-search" role="tab" data-toggle="tab" 
class=""><i class="fa fa-search"></i> Search</a></li>
+        <li role="presentation" class="tab col-sm-5"><a 
href="#tab-classification" aria-controls="tab-classification" 
data-name="tab-classification" role="tab" data-toggle="tab"><i class="fa 
fa-tags"></i> Classification</a></li>
+         <li role="presentation" class="tab col-sm-4"><a href="#tab-glossary" 
aria-controls="tab-glossary" data-name="tab-glossary" role="tab" 
data-toggle="tab"><i class="fa fa-folder-open"></i> Glossary</a></li>
     </ul>
 </ul>
 <div class="tab-content">
-    <div role="tabpanel" class="tab-pane" id="tab-tag">
+    <div role="tabpanel" class="tab-pane" id="tab-classification">
         <div id="r_tagLayoutView"></div>
     </div>
     <div role="tabpanel" class="tab-pane" id="tab-search">
         <div id="r_searchLayoutView"></div>
     </div>
+    <div role="tabpanel" class="tab-pane" id="tab-glossary">
+        <div id="r_glossaryLayoutView"></div>
+    </div>
 </div>

http://git-wip-us.apache.org/repos/asf/atlas/blob/3709842a/dashboardv2/public/js/utils/CommonViewFunction.js
----------------------------------------------------------------------
diff --git a/dashboardv2/public/js/utils/CommonViewFunction.js 
b/dashboardv2/public/js/utils/CommonViewFunction.js
index 0e097d4..bc5c170 100644
--- a/dashboardv2/public/js/utils/CommonViewFunction.js
+++ b/dashboardv2/public/js/utils/CommonViewFunction.js
@@ -233,7 +233,7 @@ define(['require', 'utils/Utils', 'modules/Modal', 
'utils/Messages', 'utils/Enum
     }
     CommonViewFunction.tagForTable = function(obj) {
         var traits = obj.classifications,
-            atags = "",
+            tagHtml = "",
             addTag = "",
             popTag = "",
             count = 0,
@@ -251,7 +251,7 @@ define(['require', 'utils/Utils', 'modules/Modal', 
'utils/Messages', 'utils/Enum
                 if (count >= 1) {
                     popTag += tagString;
                 } else {
-                    atags += tagString;
+                    tagHtml += tagString;
                 }
                 ++count;
             });
@@ -264,9 +264,41 @@ define(['require', 'utils/Utils', 'modules/Modal', 
'utils/Messages', 'utils/Enum
             }
         }
         if (count > 1) {
-            addTag += '<div data-id="showMoreLess" class="btn btn-action 
btn-sm assignTag"><i class="fa fa-ellipsis-h" aria-hidden="true"></i><div 
class="popup-tag">' + popTag + '</div></div>'
+            addTag += '<div data-id="showMoreLess" class="btn btn-action 
btn-sm assignTag"><i class="fa fa-ellipsis-h" aria-hidden="true"></i><div 
class="popup-tag-term">' + popTag + '</div></div>'
         }
-        return '<div class="tagList btn-inline btn-fixed-width">' + atags + 
addTag + '</div>';
+        return '<div class="tagList btn-inline btn-fixed-width">' + tagHtml + 
addTag + '</div>';
+    }
+    CommonViewFunction.termForTable = function(obj) {
+        var terms = obj.meanings,
+            termHtml = "",
+            addTerm = "",
+            popTerm = "",
+            count = 0,
+            entityName = Utils.getName(obj);
+        if (terms) {
+            terms.map(function(term) {
+                var className = "btn btn-action btn-sm btn-blue btn-icon",
+                    deleteIcon = '<i class="fa fa-times" data-id="delete"  
data-assetname="' + entityName + '"data-name="' + term.typeName + '" 
data-type="tag" data-guid="' + obj.guid + '" data-termGuid="' + term.termGuid + 
'" ></i>',
+                    termString = '<a class="' + className + '" 
data-id="termClick"><span title="' + term.typeName + '">' + term.displayText + 
'</span>' + deleteIcon + '</a>';
+                if (count >= 1) {
+                    popTerm += termString;
+                } else {
+                    termHtml += termString;
+                }
+                ++count;
+            });
+        }
+        if (!Enums.entityStateReadOnly[obj.status]) {
+            if (obj.guid) {
+                addTerm += '<a href="javascript:void(0)" data-id="addTerm" 
class="btn btn-action btn-sm assignTag" data-guid="' + obj.guid + '" ><i 
class="fa fa-plus"></i></a>';
+            } else {
+                addTerm += '<a href="javascript:void(0)" data-id="addTerm" 
class="btn btn-action btn-sm assignTag"><i style="right:0" class="fa 
fa-plus"></i></a>';
+            }
+        }
+        if (count > 1) {
+            addTerm += '<div data-id="showMoreLess" class="btn btn-action 
btn-sm assignTerm"><i class="fa fa-ellipsis-h" aria-hidden="true"></i><div 
class="popup-tag-term">' + popTerm + '</div></div>'
+        }
+        return '<div class="tagList btn-inline btn-fixed-width">' + termHtml + 
addTerm + '</div>';
     }
     CommonViewFunction.generateQueryOfFilter = function(value) {
         var entityFilters = CommonViewFunction.attributeFilter.extractUrl({ 
"value": value.entityFilters, "formatDate": true }),
@@ -538,6 +570,183 @@ define(['require', 'utils/Utils', 'modules/Modal', 
'utils/Messages', 'utils/Enum
             }
         }
     }
+    CommonViewFunction.createEditGlossaryCategoryTerm = function(options) {
+        if (options) {
+            var model = options.model,
+                isTermView = options.isTermView,
+                isGlossaryView = options.isGlossaryView,
+                collection = options.collection
+        }
+        require([
+            'views/glossary/CreateEditCategoryTermLayoutView',
+            'views/glossary/CreateEditGlossaryLayoutView',
+            'modules/Modal'
+        ], function(CreateEditCategoryTermLayoutView, 
CreateEditGlossaryLayoutView, Modal) {
+            var view = null,
+                title = null;
+            if (isGlossaryView) {
+                view = new CreateEditGlossaryLayoutView({ 
"glossaryCollection": collection, "model": model });
+                title = "Glossary";
+            } else {
+                view = new CreateEditCategoryTermLayoutView({ 
"glossaryCollection": collection, "modelJSON": model });
+                title = (isTermView ? 'Term' : 'Category');
+            }
+
+            var modal = new Modal({
+                "title": ((model ? "Update " : "Create ") + title),
+                "content": view,
+                "cancelText": "Cancel",
+                "okCloses": false,
+                "okText": model ? "Update" : "Create",
+                "allowCancel": true
+            }).open();
+            modal.on('ok', function() {
+                if (isGlossaryView) {
+                    modal.$el.find('button.ok').attr("disabled", "true");
+                }
+                
CommonViewFunction.createEditGlossaryCategoryTermSubmit(_.extend({ "ref": view, 
"modal": modal }, options));
+            });
+            modal.on('closeModal', function() {
+                modal.trigger('cancel');
+                if (options.onModalClose) {
+                    options.onModalClose()
+                }
+            });
+        });
+    }
+    CommonViewFunction.createEditGlossaryCategoryTermSubmit = 
function(options) {
+        if (options) {
+            var ref = options.ref,
+                modal = options.modal,
+                model = options.model,
+                node = options.node,
+                isTermView = options.isTermView,
+                isCategoryView = options.isCategoryView,
+                collection = options.collection,
+                isGlossaryView = options.isGlossaryView,
+                data = ref.ui[(isGlossaryView ? "glossaryForm" : 
"categoryTermForm")].serializeArray().reduce(function(obj, item) {
+                    obj[item.name] = item.value;
+                    return obj;
+                }, {}),
+                newModel = new options.collection.model(),
+                messageType = "Glossary ";
+        }
+        if (isTermView) {
+            messageType = "Term ";
+        } else if (isCategoryView) {
+            messageType = "Category ";
+        }
+        var ajaxOptions = {
+            success: function(rModel, response) {
+                Utils.notifySuccess({
+                    content: messageType + ref.ui.displayName.val() + 
Messages[model ? "editSuccessMessage" : "addSuccessMessage"]
+                });
+                if (options.callback) {
+                    options.callback(response);
+                }
+                modal.trigger('closeModal');
+            }
+        }
+        if (model) {
+            if (isGlossaryView) {
+                model.set(data).save(null, ajaxOptions)
+            } else {
+                newModel[isTermView ? "createEditTerm" : 
"createEditCategory"](_.extend(ajaxOptions, {
+                    guid: model.guid,
+                    data: JSON.stringify(_.extend({}, model, data)),
+                }));
+            }
+
+        } else {
+            if (isGlossaryView) {
+                new collection.model().set(data).save(null, ajaxOptions);
+            } else {
+                if (node) {
+                    var key = "anchor",
+                        guidKey = "glossaryGuid";
+                    data["anchor"] = {
+                        "glossaryGuid": node.glossaryId || node.guid,
+                        "displayText": node.glossaryName || node.text
+                    }
+                    if (node.type == "GlossaryCategory") {
+                        data["parentCategory"] = {
+                            "categoryGuid": node.guid
+                        }
+                    }
+                }
+                newModel[isTermView ? "createEditTerm" : 
"createEditCategory"](_.extend(ajaxOptions, {
+                    data: JSON.stringify(data),
+                }));
+            }
+        }
+
+    }
+    CommonViewFunction.removeCategoryTermAssociation = function(options) {
+        if (options) {
+            var selectedGuid = options.guid,
+                termGuid = options.termGuid,
+                isCategoryView = options.isCategoryView,
+                isTermView = options.isTermView,
+                isEntityView = options.isEntityView,
+                collection = options.collection,
+                model = options.model,
+                newModel = new options.collection.model(),
+                ajaxOptions = {
+                    success: function(rModel, response) {
+                        Utils.notifySuccess({
+                            content: ((isCategoryView ? "Term" : "Category") + 
" association is removed successfully")
+                        });
+                        if (options.callback) {
+                            options.callback();
+                        }
+                        modal.trigger('closeModal');
+                    },
+                    cust_error: function() {
+                        if (options.hideLoader) {
+                            options.hideLoader();
+                        }
+                    }
+                },
+                modal = new Modal({
+                    title: options.titleMessage,
+                    okText: options.buttonText,
+                    htmlContent: options.msg,
+                    cancelText: "Cancel",
+                    allowCancel: true,
+                    okCloses: true,
+                    showFooter: true,
+                }).open();
+            modal.on('ok', function() {
+                if (options.showLoader) {
+                    options.showLoader();
+                }
+                if (isEntityView && model) {
+                    var data = [model];
+                    newModel.removeTermFromEntity(termGuid, 
_.extend(ajaxOptions, {
+                        data: JSON.stringify(data)
+                    }))
+                } else {
+                    var data = _.extend({}, model);
+                    if (isTermView) {
+                        data.categories = _.reject(data.categories, 
function(term) { return term.categoryGuid != selectedGuid });
+                    } else {
+                        data.terms = _.reject(data.terms, function(term) { 
return term.termGuid != selectedGuid });
+                    }
+
+                    newModel[isTermView ? "createEditTerm" : 
"createEditCategory"](_.extend(ajaxOptions, {
+                        guid: model.guid,
+                        data: JSON.stringify(_.extend({}, model, data)),
+                    }));
+                }
+            });
+            modal.on('closeModal', function() {
+                modal.trigger('cancel');
+                if (options.onModalClose) {
+                    options.onModalClose()
+                }
+            });
+        }
+    }
     CommonViewFunction.addRestCsrfCustomHeader = function(xhr, settings) {
         //    if (settings.url == null || 
!settings.url.startsWith('/webhdfs/')) {
         if (settings.url == null) {

http://git-wip-us.apache.org/repos/asf/atlas/blob/3709842a/dashboardv2/public/js/utils/Globals.js
----------------------------------------------------------------------
diff --git a/dashboardv2/public/js/utils/Globals.js 
b/dashboardv2/public/js/utils/Globals.js
index 6225715..d9df82a 100644
--- a/dashboardv2/public/js/utils/Globals.js
+++ b/dashboardv2/public/js/utils/Globals.js
@@ -27,7 +27,8 @@ define(['require'], function(require) {
         tabState: {
             stateChanged: false,
             tagUrl: "#!/tag",
-            searchUrl: "#!/search"
+            searchUrl: "#!/search",
+            glossaryUrl: "#!/glossary"
         },
         detailPageState: {}
     };

http://git-wip-us.apache.org/repos/asf/atlas/blob/3709842a/dashboardv2/public/js/utils/Messages.js
----------------------------------------------------------------------
diff --git a/dashboardv2/public/js/utils/Messages.js 
b/dashboardv2/public/js/utils/Messages.js
index 1c733ff..718cbb8 100644
--- a/dashboardv2/public/js/utils/Messages.js
+++ b/dashboardv2/public/js/utils/Messages.js
@@ -46,7 +46,13 @@ define(['require'], function(require) {
         tag: {
             addAttributeSuccessMessage: "Classification attribute is added 
successfully",
             updateTagDescriptionMessage: "Classification description is 
updated successfully"
+        },
+        glossary: {
+            removeTermfromCategory: "Remove Term Assignment",
+            removeTermfromEntity: "Remove Term Assignment",
+            removeCategoryfromTerm: "Remove Category Assignment"
         }
+
     };
     return Messages;
 });
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/atlas/blob/3709842a/dashboardv2/public/js/utils/UrlLinks.js
----------------------------------------------------------------------
diff --git a/dashboardv2/public/js/utils/UrlLinks.js 
b/dashboardv2/public/js/utils/UrlLinks.js
index b9f3805..2e5eefe 100644
--- a/dashboardv2/public/js/utils/UrlLinks.js
+++ b/dashboardv2/public/js/utils/UrlLinks.js
@@ -120,6 +120,51 @@ define(['require', 'utils/Enums', 'utils/Utils', 
'underscore'], function(require
                 return saveSearchUrl;
             }
         },
+        glossaryApiUrl: function(options) {
+            var guid = options && options.guid,
+                glossaryUrl = this.baseUrlV2 + '/glossary';
+            if (guid) {
+                return glossaryUrl + '/' + guid;
+            } else {
+                return glossaryUrl;
+            }
+        },
+        categoryApiUrl: function(options) {
+            var guid = options && options.guid,
+                list = options && options.list,
+                related = options && options.related,
+                categoryUrl = this.glossaryApiUrl() + '/' + (list ? 
'categories' : 'category');
+            if (guid) {
+                if (related) {
+                    return categoryUrl + '/' + guid + "/related";
+                } else {
+                    return categoryUrl + '/' + guid;
+                }
+            } else {
+                return categoryUrl;
+            }
+        },
+        termApiUrl: function(options) {
+            var guid = options && options.guid,
+                list = options && options.list,
+                related = options && options.related,
+                termUrl = this.glossaryApiUrl() + '/' + (list ? 'terms' : 
'term');
+            if (guid) {
+                if (related) {
+                    return termUrl + '/' + guid + "/related";
+                } else {
+                    return termUrl + '/' + guid;
+                }
+            } else {
+                return termUrl;
+            }
+        },
+        termToEntityApiUrl: function(guid) {
+            var termUrl = this.termApiUrl({ list: true });
+            if (guid) {
+                return termUrl + '/' + guid + '/assignedEntities';
+            }
+        },
         versionApiUrl: function() {
             return this.baseUrl + '/admin/version';
         },

http://git-wip-us.apache.org/repos/asf/atlas/blob/3709842a/dashboardv2/public/js/utils/Utils.js
----------------------------------------------------------------------
diff --git a/dashboardv2/public/js/utils/Utils.js 
b/dashboardv2/public/js/utils/Utils.js
index 5024b8f..ff6b5ff 100644
--- a/dashboardv2/public/js/utils/Utils.js
+++ b/dashboardv2/public/js/utils/Utils.js
@@ -283,6 +283,8 @@ define(['require', 'utils/Globals', 'pnotify', 
'utils/Messages', 'utils/Enums',
                     urlUpdate['tagUrl'] = options.url;
                 } else if (Utils.getUrlState.isSearchTab(options.url)) {
                     urlUpdate['searchUrl'] = options.url;
+                } else if (Utils.getUrlState.isGlossaryTab(options.url)) {
+                    urlUpdate['glossaryUrl'] = options.url;
                 }
                 $.extend(Globals.saveApplicationState.tabState, urlUpdate);
             }
@@ -313,6 +315,9 @@ define(['require', 'utils/Globals', 'pnotify', 
'utils/Messages', 'utils/Enums',
         isSearchTab: function(url) {
             return this.getQueryUrl(url).firstValue == "search";
         },
+        isGlossaryTab: function(url) {
+            return this.getQueryUrl(url).firstValue == "glossary";
+        },
         isDetailPage: function(url) {
             return this.getQueryUrl(url).firstValue == "detailPage";
         },

http://git-wip-us.apache.org/repos/asf/atlas/blob/3709842a/dashboardv2/public/js/views/detail_page/DetailPageLayoutView.js
----------------------------------------------------------------------
diff --git a/dashboardv2/public/js/views/detail_page/DetailPageLayoutView.js 
b/dashboardv2/public/js/views/detail_page/DetailPageLayoutView.js
index 99e9602..5d5ad2b 100644
--- a/dashboardv2/public/js/views/detail_page/DetailPageLayoutView.js
+++ b/dashboardv2/public/js/views/detail_page/DetailPageLayoutView.js
@@ -50,6 +50,7 @@ define(['require',
             /** ui selector cache */
             ui: {
                 tagClick: '[data-id="tagClick"]',
+                termClick: '[data-id="termClick"]',
                 propagatedTagDiv: '[data-id="propagatedTagDiv"]',
                 title: '[data-id="title"]',
                 editButton: '[data-id="editButton"]',
@@ -57,8 +58,11 @@ define(['require',
                 description: '[data-id="description"]',
                 editBox: '[data-id="editBox"]',
                 deleteTag: '[data-id="deleteTag"]',
+                deleteTerm: '[data-id="deleteTerm"]',
                 addTag: '[data-id="addTag"]',
+                addTerm: '[data-id="addTerm"]',
                 tagList: '[data-id="tagList"]',
+                termList: '[data-id="termList"]',
                 propagatedTagList: '[data-id="propagatedTagList"]',
                 fullscreenPanel: "#fullscreen_panel",
                 tablist: '[data-id="tab-list"] li'
@@ -81,7 +85,19 @@ define(['require',
                         });
                     }
                 };
+                events["click " + this.ui.termClick] = function(e) {
+                    if (e.target.nodeName.toLocaleLowerCase() != "i") {
+                        Utils.setUrl({
+                            url: '#!/glossary/' + 
$(e.currentTarget).find('i').data('guid'),
+                            mergeBrowserUrl: false,
+                            urlParams: { gType: "term" },
+                            trigger: true
+                        });
+                    }
+                };
+                events["click " + this.ui.addTerm] = 'onClickAddTermBtn';
                 events["click " + this.ui.deleteTag] = 'onClickTagCross';
+                events["click " + this.ui.deleteTerm] = 'onClickTermCross';
                 events["click " + this.ui.addTag] = 'onClickAddTagBtn';
                 events["click " + this.ui.tablist] = function(e) {
                     var tabValue = $(e.currentTarget).attr('role');
@@ -101,7 +117,7 @@ define(['require',
              * @constructs
              */
             initialize: function(options) {
-                _.extend(this, _.pick(options, 'value', 'collection', 'id', 
'entityDefCollection', 'typeHeaders', 'enumDefCollection', 
'classificationDefCollection'));
+                _.extend(this, _.pick(options, 'value', 'collection', 'id', 
'entityDefCollection', 'typeHeaders', 'enumDefCollection', 
'classificationDefCollection', 'glossaryCollection'));
                 this.bindEvents();
                 $('body').addClass("detail-page");
             },
@@ -156,6 +172,9 @@ define(['require',
                         } else {
                             this.generateTag([]);
                         }
+                        if (collectionJSON.relationshipAttributes && 
collectionJSON.relationshipAttributes.meanings) {
+                            
this.generateTerm(collectionJSON.relationshipAttributes.meanings);
+                        }
                         if (Globals.entityTypeConfList && 
_.isEmptyArray(Globals.entityTypeConfList)) {
                             this.ui.editButtonContainer.html(ButtonsTmpl({ 
btn_edit: true }));
                         } else {
@@ -326,6 +345,30 @@ define(['require',
                     }
                 }));
             },
+            onClickTermCross: function(e) {
+                var $el = $(e.currentTarget),
+                    termGuid = $el.data('guid'),
+                    termName = $el.text(),
+                    that = this,
+                    termObj = 
_.find(this.collection.first().get('entity').relationshipAttributes.meanings, { 
guid: termGuid });
+                CommonViewFunction.removeCategoryTermAssociation({
+                    termGuid: termGuid,
+                    model: {
+                        guid: that.id,
+                        relationshipGuid: termObj.relationshipGuid
+                    },
+                    collection: that.glossaryCollection,
+                    msg: "<div class='ellipsis'>Remove: " + "<b>" + 
_.escape(termName) + "</b> assignment from" + " " + "<b>" + this.name + 
"?</b></div>",
+                    titleMessage: Messages.glossary.removeTermfromEntity,
+                    isEntityView: true,
+                    buttonText: "Remove",
+                    showLoader: that.showLoader.bind(that),
+                    hideLoader: that.hideLoader.bind(that),
+                    callback: function() {
+                        that.fetchCollection();
+                    }
+                });
+            },
             generateTag: function(tagObject) {
                 var that = this,
                     tagData = "",
@@ -338,7 +381,7 @@ define(['require',
                     val.entityGuid === that.id ? tag['self'].push(val) : 
tag['propagated'].push(val);
                 });
                 _.each(tag.self, function(val) {
-                    tagData += '<span class="btn btn-action btn-sm btn-icon 
btn-blue" title=' + val.typeName + ' data-id="tagClick"><span>' + val.typeName 
+ '</span><i class="fa fa-close" data-id="deleteTag" data-type="tag" 
title="Delete Tag"></i></span>';
+                    tagData += '<span class="btn btn-action btn-sm btn-icon 
btn-blue" title=' + val.typeName + ' data-id="tagClick"><span>' + val.typeName 
+ '</span><i class="fa fa-close" data-id="deleteTag" data-type="tag" 
title="Remove Tag"></i></span>';
                 });
                 _.each(tag.propagated, function(val) {
                     propagatedTagListData += '<span class="btn btn-action 
btn-sm btn-icon btn-blue" title=' + val.typeName + ' data-id="tagClick"><span>' 
+ val.typeName + '</span></span>';
@@ -350,6 +393,15 @@ define(['require',
                 this.ui.propagatedTagList.html(propagatedTagListData);
 
             },
+            generateTerm: function(data) {
+                var that = this,
+                    termData = "";
+                _.each(data, function(val) {
+                    termData += '<span class="btn btn-action btn-sm btn-icon 
btn-blue" title=' + val.displayText + ' data-id="termClick"><span>' + 
val.displayText + '</span><i class="fa fa-close" data-id="deleteTerm" 
data-guid="' + val.guid + '" data-type="term" title="Remove Term"></i></span>';
+                });
+                this.ui.termList.find("span.btn").remove();
+                this.ui.termList.prepend(termData);
+            },
             hideLoader: function() {
                 Utils.hideTitleLoader(this.$('.page-title .fontLoader'), 
this.$('.entityDetail'));
             },
@@ -381,6 +433,23 @@ define(['require',
                     });
                 });
             },
+            onClickAddTermBtn: function(e) {
+                var that = this;
+                require(['views/glossary/AssignTermLayoutView'], 
function(AssignTermLayoutView) {
+                    var view = new AssignTermLayoutView({
+                        guid: that.id,
+                        callback: function() {
+                            that.fetchCollection();
+                        },
+                        showLoader: that.showLoader.bind(that),
+                        hideLoader: that.hideLoader.bind(that),
+                        glossaryCollection: that.glossaryCollection
+                    });
+                    view.modal.on('ok', function() {
+                        Utils.showTitleLoader(that.$('.page-title 
.fontLoader'), that.$('.entityDetail'));
+                    });
+                });
+            },
             renderEntityDetailTableLayoutView: function(obj) {
                 var that = this;
                 require(['views/entity/EntityDetailTableLayoutView'], 
function(EntityDetailTableLayoutView) {

http://git-wip-us.apache.org/repos/asf/atlas/blob/3709842a/dashboardv2/public/js/views/glossary/AssignTermLayoutView.js
----------------------------------------------------------------------
diff --git a/dashboardv2/public/js/views/glossary/AssignTermLayoutView.js 
b/dashboardv2/public/js/views/glossary/AssignTermLayoutView.js
new file mode 100644
index 0000000..fd7631d
--- /dev/null
+++ b/dashboardv2/public/js/views/glossary/AssignTermLayoutView.js
@@ -0,0 +1,151 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+define(['require',
+    'backbone',
+    'hbs!tmpl/glossary/AssignTermLayoutViewTmpl',
+    'utils/Utils',
+    'utils/UrlLinks',
+    'modules/Modal'
+], function(require, Backbone, AssignTermLayoutViewTmpl, Utils, UrlLinks, 
Modal) {
+
+    var AssignTermLayoutView = Backbone.Marionette.LayoutView.extend(
+        /** @lends AssignTermLayoutView */
+        {
+            _viewName: 'AssignTermLayoutView',
+
+            template: AssignTermLayoutViewTmpl,
+
+            templateHelpers: function() {
+                return {};
+            },
+
+            /** Layout sub regions */
+            regions: {
+                RGlossaryTree: "#r_glossaryTree"
+            },
+
+            /** ui selector cache */
+            ui: {},
+            /** ui events hash */
+            events: function() {
+                var events = {};
+                return events;
+            },
+            /**
+             * intialize a new AssignTermLayoutView Layout
+             * @constructs
+             */
+            initialize: function(options) {
+                _.extend(this, _.pick(options, 'glossaryCollection', 'guid', 
'callback', 'hideLoader', 'isCategoryView', 'categoryData', 'isTermView', 
'termData'));
+                var that = this;
+                this.options = options;
+                if (!this.isCategoryView && !this.isTermView) {
+                    this.isEntityView = true;
+                }
+                this.glossary = {
+                    selectedItem: {}
+                }
+                var title = "";
+                if (this.isCategoryView || this.isEntityView) {
+                    title = ("Assign term to " + (this.isCategoryView ? 
"Category" : "entity"))
+                } else {
+                    title = "Assign Category to term";
+                }
+                this.modal = new Modal({
+                    "title": title,
+                    "content": this,
+                    "cancelText": "Cancel",
+                    "okCloses": false,
+                    "okText": "Assign",
+                    "allowCancel": true
+                });
+                this.modal.open();
+                this.modal.on('closeModal', function() {
+                    that.modal.trigger('cancel');
+                    if (that.assignTermError && that.hideLoader) {
+                        that.hideLoader();
+                    }
+                    if (options.onModalClose) {
+                        options.onModalClose()
+                    }
+                });
+                this.modal.on('ok', function() {
+                    that.assignTerm();
+                });
+            },
+            bindEvents: function() {},
+            onRender: function() {
+                this.renderGlossaryTree();
+            },
+            assignTerm: function() {
+                this.assignTermError = false;
+                var that = this,
+                    data = [],
+                    selectedItem = this.glossary.selectedItem,
+                    selectedGuid = selectedItem.guid,
+                    ajaxOptions = {
+                        success: function(rModel, response) {
+                            Utils.notifySuccess({
+                                content: (that.isCategoryView ? "Term" : 
"Category") + " is associated successfully "
+                            });
+                            that.modal.trigger('closeModal');
+                            if (that.callback) {
+                                that.callback();
+                            }
+                        },
+                        cust_error: function() {
+                            that.assignTermError = true;
+                        }
+                    },
+                    model = new this.glossaryCollection.model();
+                if (this.isCategoryView) {
+                    data = _.extend({}, this.categoryData);
+                    if (data.terms) {
+                        data.terms.push({ "termGuid": selectedGuid });
+                    } else {
+                        data.terms = [{ "termGuid": selectedGuid }];
+                    }
+                    model.assignTermToCategory(_.extend(ajaxOptions, { data: 
JSON.stringify(data), guid: data.guid }));
+                } else if (this.isTermView) {
+                    data = _.extend({}, this.termData);
+                    if (data.categories) {
+                        data.categories.push({ "categoryGuid": selectedGuid });
+                    } else {
+                        data.categories = [{ "categoryGuid": selectedGuid }];
+                    }
+                    model.assignCategoryToTerm(_.extend(ajaxOptions, { data: 
JSON.stringify(data), guid: data.guid }));
+                } else {
+                    data.push({ "guid": that.guid });
+                    model.assignTermToEntity(selectedGuid, 
_.extend(ajaxOptions, { data: JSON.stringify(data) }));
+                }
+            },
+            renderGlossaryTree: function() {
+                var that = this;
+                require(['views/glossary/GlossaryLayoutView'], 
function(GlossaryLayoutView) {
+                    that.RGlossaryTree.show(new GlossaryLayoutView(_.extend({
+                        "isAssignTermView": that.isCategoryView,
+                        "isAssignCategoryView": that.isTermView,
+                        "isAssignEntityView": that.isEntityView,
+                        "glossary": that.glossary
+                    }, that.options)));
+                });
+            },
+        });
+    return AssignTermLayoutView;
+});
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/atlas/blob/3709842a/dashboardv2/public/js/views/glossary/CreateEditCategoryTermLayoutView.js
----------------------------------------------------------------------
diff --git 
a/dashboardv2/public/js/views/glossary/CreateEditCategoryTermLayoutView.js 
b/dashboardv2/public/js/views/glossary/CreateEditCategoryTermLayoutView.js
new file mode 100644
index 0000000..c884229
--- /dev/null
+++ b/dashboardv2/public/js/views/glossary/CreateEditCategoryTermLayoutView.js
@@ -0,0 +1,70 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+define(['require',
+    'backbone',
+    'hbs!tmpl/glossary/CreateEditCategoryTermLayoutView_tmpl',
+    'utils/Utils',
+    'utils/UrlLinks'
+], function(require, Backbone, CreateEditCategoryTermLayoutViewTmpl, Utils, 
UrlLinks) {
+
+    var CreateEditCategoryTermLayoutView = 
Backbone.Marionette.LayoutView.extend(
+        /** @lends CreateEditCategoryTermLayoutView */
+        {
+            _viewName: 'CreateEditCategoryTermLayoutView',
+
+            template: CreateEditCategoryTermLayoutViewTmpl,
+
+            templateHelpers: function() {
+                return {
+                    create: this.create,
+                    modelJSON: this.modelJSON
+                };
+            },
+
+            /** Layout sub regions */
+            regions: {},
+
+            /** ui selector cache */
+            ui: {
+                "qualifiedName": "[data-id='qualifiedName']",
+                "displayName": "[data-id='displayName']",
+                "shortDescription": "[data-id='shortDescription']",
+                "longDescription": "[data-id='longDescription']",
+                "categoryTermForm": "[data-id='categoryTermForm']"
+            },
+            /** ui events hash */
+            events: function() {
+                var events = {};
+                return events;
+            },
+            /**
+             * intialize a new CreateEditCategoryTermLayoutView Layout
+             * @constructs
+             */
+            initialize: function(options) {
+                _.extend(this, _.pick(options, 'glossaryCollection', 
'modelJSON'));
+                if (!this.modelJSON) {
+                    this.create = true;
+                }
+            },
+            bindEvents: function() {},
+            onRender: function() {}
+        });
+    return CreateEditCategoryTermLayoutView;
+});
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/atlas/blob/3709842a/dashboardv2/public/js/views/glossary/CreateEditGlossaryLayoutView.js
----------------------------------------------------------------------
diff --git 
a/dashboardv2/public/js/views/glossary/CreateEditGlossaryLayoutView.js 
b/dashboardv2/public/js/views/glossary/CreateEditGlossaryLayoutView.js
new file mode 100644
index 0000000..e06b05b
--- /dev/null
+++ b/dashboardv2/public/js/views/glossary/CreateEditGlossaryLayoutView.js
@@ -0,0 +1,69 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+define(['require',
+    'backbone',
+    'hbs!tmpl/glossary/CreateEditGlossaryLayoutView_tmpl',
+    'utils/Utils',
+    'utils/UrlLinks'
+], function(require, Backbone, CreateEditGlossaryLayoutViewTmpl, Utils, 
UrlLinks) {
+
+    var CreateEditGlossaryLayoutView = Backbone.Marionette.LayoutView.extend(
+        /** @lends CreateEditGlossaryLayoutView */
+        {
+            _viewName: 'CreateEditGlossaryLayoutView',
+
+            template: CreateEditGlossaryLayoutViewTmpl,
+
+            templateHelpers: function() {
+                return {
+                    create: this.create
+                };
+            },
+
+            /** Layout sub regions */
+            regions: {},
+
+            /** ui selector cache */
+            ui: {
+                "qualifiedName": "[data-id='qualifiedName']",
+                "displayName": "[data-id='displayName']",
+                "shortDescription": "[data-id='shortDescription']",
+                "longDescription": "[data-id='longDescription']",
+                "glossaryForm": "[data-id='glossaryForm']"
+            },
+            /** ui events hash */
+            events: function() {
+                var events = {};
+                return events;
+            },
+            /**
+             * intialize a new CreateEditGlossaryLayoutView Layout
+             * @constructs
+             */
+            initialize: function(options) {
+                _.extend(this, _.pick(options, 'glossaryCollection', 'model'));
+                if (!this.model) {
+                    this.create = true;
+                }
+            },
+            bindEvents: function() {},
+            onRender: function() {}
+        });
+    return CreateEditGlossaryLayoutView;
+});
\ No newline at end of file

Reply via email to