You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@atlas.apache.org by sa...@apache.org on 2019/10/09 17:33:40 UTC

[atlas] branch branch-2.0 updated: ATLAS-3439: Add User-defined properties in entity details page.

This is an automated email from the ASF dual-hosted git repository.

sarath pushed a commit to branch branch-2.0
in repository https://gitbox.apache.org/repos/asf/atlas.git


The following commit(s) were added to refs/heads/branch-2.0 by this push:
     new f5a9e62  ATLAS-3439: Add User-defined properties in entity details page.
f5a9e62 is described below

commit f5a9e62500513c0f17034550479880f2738ecdca
Author: sameer79 <fi...@yahoo.co.in>
AuthorDate: Wed Oct 9 17:35:12 2019 +0530

    ATLAS-3439: Add User-defined properties in entity details page.
    
    Signed-off-by: Sarath Subramanian <sa...@apache.org>
    (cherry picked from commit 503a572d8d4fce5866100fb38ed51fbd0f90ba71)
---
 ATLAS-3439-1.patch                                 | 1401 ++++++++++++++++++++
 dashboardv2/public/css/scss/common.scss            |   47 +-
 dashboardv2/public/css/scss/override.scss          |    3 +-
 dashboardv2/public/css/scss/panel.scss             |   36 +-
 .../detail_page/DetailPageLayoutView_tmpl.html     |   15 +-
 .../entity/EntityDetailTableLayoutView_tmpl.html   |   44 +-
 .../entity/EntityUserDefineItemView_tmpl.html      |   45 +
 .../entity/EntityUserDefineView_tmpl.html          |   73 +
 .../js/views/detail_page/DetailPageLayoutView.js   |   12 +-
 .../js/views/entity/EntityDetailTableLayoutView.js |    2 +-
 .../js/views/entity/EntityUserDefineItemView.js    |   98 ++
 .../public/js/views/entity/EntityUserDefineView.js |  184 +++
 dashboardv3/public/css/scss/common.scss            |   43 +
 dashboardv3/public/css/scss/panel.scss             |   36 +-
 dashboardv3/public/css/scss/table.scss             |    1 +
 .../detail_page/DetailPageLayoutView_tmpl.html     |   15 +-
 .../entity/EntityDetailTableLayoutView_tmpl.html   |   44 +-
 .../entity/EntityUserDefineItemView_tmpl.html      |   45 +
 .../entity/EntityUserDefineView_tmpl.html          |   80 ++
 .../js/views/detail_page/DetailPageLayoutView.js   |   12 +-
 .../js/views/entity/EntityDetailTableLayoutView.js |    2 +-
 .../js/views/entity/EntityUserDefineItemView.js    |   98 ++
 .../public/js/views/entity/EntityUserDefineView.js |  184 +++
 23 files changed, 2467 insertions(+), 53 deletions(-)

diff --git a/ATLAS-3439-1.patch b/ATLAS-3439-1.patch
new file mode 100644
index 0000000..410f5a3
--- /dev/null
+++ b/ATLAS-3439-1.patch
@@ -0,0 +1,1401 @@
+From 8e806aae327b3179a26e6627fd42c80f6ec615f4 Mon Sep 17 00:00:00 2001
+From: sameer79 <fi...@yahoo.co.in>
+Date: Wed, 9 Oct 2019 17:35:12 +0530
+Subject: [PATCH] ATLAS-3439: Add User-defined properties in entity details
+ page.
+
+---
+ dashboardv2/public/css/scss/common.scss            |  47 +++++-
+ dashboardv2/public/css/scss/override.scss          |   3 +-
+ dashboardv2/public/css/scss/panel.scss             |  35 +++-
+ .../detail_page/DetailPageLayoutView_tmpl.html     |  15 +-
+ .../entity/EntityDetailTableLayoutView_tmpl.html   |  44 +++--
+ .../entity/EntityUserDefineItemView_tmpl.html      |  45 +++++
+ .../entity/EntityUserDefineView_tmpl.html          |  65 ++++++++
+ .../templates/search/AdvancedSearchInfo_tmpl.html  |   2 +-
+ .../js/views/detail_page/DetailPageLayoutView.js   |  12 +-
+ .../js/views/entity/EntityDetailTableLayoutView.js |   2 +-
+ .../js/views/entity/EntityUserDefineItemView.js    |  98 +++++++++++
+ .../public/js/views/entity/EntityUserDefineView.js | 184 +++++++++++++++++++++
+ dashboardv3/public/css/scss/common.scss            |  43 +++++
+ dashboardv3/public/css/scss/panel.scss             |  35 +++-
+ dashboardv3/public/css/scss/table.scss             |   1 +
+ .../detail_page/DetailPageLayoutView_tmpl.html     |  15 +-
+ .../entity/EntityDetailTableLayoutView_tmpl.html   |  44 +++--
+ .../entity/EntityUserDefineItemView_tmpl.html      |  45 +++++
+ .../entity/EntityUserDefineView_tmpl.html          |  65 ++++++++
+ .../js/views/detail_page/DetailPageLayoutView.js   |  12 +-
+ .../js/views/entity/EntityDetailTableLayoutView.js |   2 +-
+ .../js/views/entity/EntityUserDefineItemView.js    |  98 +++++++++++
+ .../public/js/views/entity/EntityUserDefineView.js | 184 +++++++++++++++++++++
+ 23 files changed, 1042 insertions(+), 54 deletions(-)
+ create mode 100644 dashboardv2/public/js/templates/entity/EntityUserDefineItemView_tmpl.html
+ create mode 100644 dashboardv2/public/js/templates/entity/EntityUserDefineView_tmpl.html
+ create mode 100644 dashboardv2/public/js/views/entity/EntityUserDefineItemView.js
+ create mode 100644 dashboardv2/public/js/views/entity/EntityUserDefineView.js
+ create mode 100644 dashboardv3/public/js/templates/entity/EntityUserDefineItemView_tmpl.html
+ create mode 100644 dashboardv3/public/js/templates/entity/EntityUserDefineView_tmpl.html
+ create mode 100644 dashboardv3/public/js/views/entity/EntityUserDefineItemView.js
+ create mode 100644 dashboardv3/public/js/views/entity/EntityUserDefineView.js
+
+diff --git a/dashboardv2/public/css/scss/common.scss b/dashboardv2/public/css/scss/common.scss
+index d42e5a9..b24c3c3 100644
+--- a/dashboardv2/public/css/scss/common.scss
++++ b/dashboardv2/public/css/scss/common.scss
+@@ -15,7 +15,7 @@
+ // limitations under the License.
+ 
+ 
+-/* common.scss */ 
++/* common.scss */
+ 
+ .readOnly {
+ 
+@@ -201,4 +201,47 @@ pre {
+     .panel-default>.panel-heading {
+         cursor: pointer;
+     }
+-}
+\ No newline at end of file
++}
++
++.custom-table {
++    width: 100%;
++
++    .custom-tr {
++        margin-left: 15px;
++        margin-right: 15px;
++
++        .custom-col-0,
++        .custom-col-1,
++        .custom-col-2 {
++            vertical-align: top;
++            display: inline-block;
++
++            textarea {
++                resize: vertical;
++                height: 34px;
++                min-height: 34px;
++                max-height: 70px;
++            }
++        }
++
++
++        .custom-col-0{
++            text-align: center;
++            vertical-align: middle;
++            width: 2%;
++        }
++
++        .custom-col-1{
++            width: 43%;
++        }
++
++        .custom-col-2{
++            text-align: center;
++            width: 10%;
++        }
++    }
++}
++
++.errorMsg {
++    color: $red;
++}
+diff --git a/dashboardv2/public/css/scss/override.scss b/dashboardv2/public/css/scss/override.scss
+index c8a1d89..c95ee58 100644
+--- a/dashboardv2/public/css/scss/override.scss
++++ b/dashboardv2/public/css/scss/override.scss
+@@ -128,6 +128,7 @@ td {
+     pre.scroll-y {
+         max-height: 200px;
+         overflow-y: auto;
++        word-break: break-word;
+     }
+ }
+ 
+@@ -469,4 +470,4 @@ div.columnmanager-dropdown-container {
+ 
+ .w30 {
+     width: 30% !important;
+-}
+\ No newline at end of file
++}
+diff --git a/dashboardv2/public/css/scss/panel.scss b/dashboardv2/public/css/scss/panel.scss
+index c1ac042..52b3dbe 100644
+--- a/dashboardv2/public/css/scss/panel.scss
++++ b/dashboardv2/public/css/scss/panel.scss
+@@ -118,4 +118,37 @@
+             }
+         }
+     }
+-}
+\ No newline at end of file
++}
++
++.panel-default.custom-panel>.panel-heading {
++    color: $black;
++    cursor: pointer;
++    border-bottom: none;
++    display: inline-block;
++
++    .panel-title {
++        font-weight: normal;
++        a:hover {
++            color: $black;
++            opacity: 0.7;
++        }
++    }
++    .btn-group {
++        margin-top: 3px;
++    }
++}
++
++.panel-default.custom-panel>.panel-actions {
++    float: right;
++    margin-top: 15px;
++    button {
++        margin-right: 10px;
++    }
++}
++
++.panel-default.custom-panel>.panel-collapse>.panel-body {
++    border-top: none;
++}
++.panel-default.custom-panel>.panel-heading > .btn-group > button {
++    color: $black;
++}
+diff --git a/dashboardv2/public/js/templates/detail_page/DetailPageLayoutView_tmpl.html b/dashboardv2/public/js/templates/detail_page/DetailPageLayoutView_tmpl.html
+index c395799..d35debc 100644
+--- a/dashboardv2/public/js/templates/detail_page/DetailPageLayoutView_tmpl.html
++++ b/dashboardv2/public/js/templates/detail_page/DetailPageLayoutView_tmpl.html
+@@ -65,9 +65,16 @@
+ <div>
+     <div class="tab-content">
+         <div id="tab-details" role="properties" class="tab-pane active animated fadeIn">
+-            <div id="r_entityDetailTableLayoutView">
+-                <div class="fontLoader-relative">
+-                    <i class="fa fa-refresh fa-spin-custom"></i>
++            <div class="row">
++                <div class="col-md-6">
++                    <div id="r_entityDetailTableLayoutView">
++                        <div class="fontLoader-relative">
++                            <i class="fa fa-refresh fa-spin-custom"></i>
++                        </div>
++                    </div>
++                </div>
++                <div class="col-md-6">
++                    <div id="r_entityUserDefineView"></div>
+                 </div>
+             </div>
+         </div>
+@@ -122,4 +129,4 @@
+         </div>
+     </div>
+ </div>
+-</div>
+\ No newline at end of file
++</div>
+diff --git a/dashboardv2/public/js/templates/entity/EntityDetailTableLayoutView_tmpl.html b/dashboardv2/public/js/templates/entity/EntityDetailTableLayoutView_tmpl.html
+index 1c01077..18a9435 100644
+--- a/dashboardv2/public/js/templates/entity/EntityDetailTableLayoutView_tmpl.html
++++ b/dashboardv2/public/js/templates/entity/EntityDetailTableLayoutView_tmpl.html
+@@ -14,23 +14,33 @@
+  * See the License for the specific language governing permissions and
+  * limitations under the License.
+ -->
+-<div class="entity-detail-table">
+-    <div class="entity-detail-table-toggle">
+-        <div class="pretty p-switch p-fill">
+-            <input type="checkbox" data-id="noValueToggle" />
+-            <div class="state p-primary">
+-                <label>Show Empty Values</label>
++<div class="panel-group" id="accordion">
++    <div class="panel panel-default custom-panel expand_collapse_panel-icon" data-id="entity">
++        <div class="panel-heading" data-toggle="collapse" href="#collapse1" aria-expanded="true" style="width: 58%">
++            <h4 class="panel-title">
++                <a>Technical properties </a>
++            </h4>
++            <div class="btn-group pull-left">
++                <button type="button" title="Collapse"><i class="ec-icon fa"></i></button>
++            </div>
++        </div>
++        <div class="panel-actions">
++            <div class="pretty p-switch p-fill">
++                <input type="checkbox" data-id="noValueToggle" />
++                <div class="state p-primary">
++                    <label>Show Empty Values</label>
++                </div>
++            </div>
++        </div>
++        <div id="collapse1" class="panel-collapse collapse in">
++            <div class="panel-body">
++                    <div class="entity-detail-table">
++                        <table class="table">
++                            <tbody data-id="detailValue" class="hide-empty-value">
++                            </tbody>
++                        </table>
++                    </div>
+             </div>
+         </div>
+     </div>
+-    <table class="table table-quickMenu">
+-        <thead>
+-            <tr>
+-                <th>Key</th>
+-                <th>Value</th>
+-            </tr>
+-        </thead>
+-        <tbody data-id="detailValue" class="hide-empty-value">
+-        </tbody>
+-    </table>
+-</div>
+\ No newline at end of file
++</div>
+diff --git a/dashboardv2/public/js/templates/entity/EntityUserDefineItemView_tmpl.html b/dashboardv2/public/js/templates/entity/EntityUserDefineItemView_tmpl.html
+new file mode 100644
+index 0000000..a06039f
+--- /dev/null
++++ b/dashboardv2/public/js/templates/entity/EntityUserDefineItemView_tmpl.html
+@@ -0,0 +1,45 @@
++<!--
++ * Licensed to the Apache Software Foundation (ASF) under one or more
++ * contributor license agreements.  See the NOTICE file distributed with
++ * this work for additional information regarding copyright ownership.
++ * The ASF licenses this file to You under the Apache License, Version 2.0
++ * (the "License"); you may not use this file except in compliance with
++ * the License.  You may obtain a copy of the License at
++ *
++ *     http://www.apache.org/licenses/LICENSE-2.0
++ *
++ * Unless required by applicable law or agreed to in writing, software
++ * distributed under the License is distributed on an "AS IS" BASIS,
++ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
++ * See the License for the specific language governing permissions and
++ * limitations under the License.
++-->
++
++<div data-id="userDefineItems">
++    <table class="custom-table">
++        {{#each items}}
++            <tr class="custom-tr">
++                <td class="custom-col-1">
++                    <input placeholder="key" type="text"  data-type="key" data-index={{@index}} class="form-control" value={{key}}></input>
++                    <p class="errorMsg"></p>
++                </td >
++                <td  class="custom-col-0"> : </td >
++                <td  class="custom-col-1">
++                    <textarea placeholder="value"  data-type="value" data-index={{@index}} class="form-control" class="form-control">{{value}}</textarea>
++                    <p class="errorMsg"></p>
++                </td >
++                <td  class="custom-col-2">
++                    <button class="btn btn-default btn-sm" title=""  data-index={{@index}} data-id="deleteItem">
++                        <i class="fa fa-minus"> </i>
++                    </button>
++                    <button class="btn btn-default btn-sm" title="" data-index={{@index}} data-id="addItem">
++                        <i class="fa fa-plus"> </i>
++                    </button>
++                </td >
++            </tr>
++        {{/each}}
++        {{#ifCond items.length "===" 0}}
++            No properties have been created yet. To add a property, click <a href="javascript:void(0)" data-id="addItem">here</a>
++        {{/ifCond}}
++    </table>
++</div>
+diff --git a/dashboardv2/public/js/templates/entity/EntityUserDefineView_tmpl.html b/dashboardv2/public/js/templates/entity/EntityUserDefineView_tmpl.html
+new file mode 100644
+index 0000000..e3f4791
+--- /dev/null
++++ b/dashboardv2/public/js/templates/entity/EntityUserDefineView_tmpl.html
+@@ -0,0 +1,65 @@
++<!--
++ * Licensed to the Apache Software Foundation (ASF) under one or more
++ * contributor license agreements.  See the NOTICE file distributed with
++ * this work for additional information regarding copyright ownership.
++ * The ASF licenses this file to You under the Apache License, Version 2.0
++ * (the "License"); you may not use this file except in compliance with
++ * the License.  You may obtain a copy of the License at
++ *
++ *     http://www.apache.org/licenses/LICENSE-2.0
++ *
++ * Unless required by applicable law or agreed to in writing, software
++ * distributed under the License is distributed on an "AS IS" BASIS,
++ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
++ * See the License for the specific language governing permissions and
++ * limitations under the License.
++-->
++<div class="panel-group" id="accordion">
++    <div class="panel panel-default custom-panel expand_collapse_panel-icon" data-id="userDefine">
++        <div class="panel-heading" data-toggle="collapse" href="#collapse2" aria-expanded="true" {{#ifCond customAttibutes.length ">" 0}} style="width: 60%" {{else}} style="width: 100%" {{/ifCond}}>
++            <h4 class="panel-title">
++                <a>User-defined properties </a>
++            </h4>
++            <div class="btn-group pull-left">
++                <button type="button" title="Collapse"><i class="ec-icon fa"></i></button>
++            </div>
++        </div>
++        {{#ifCond customAttibutes.length ">" 0}}
++            <div class="panel-actions">
++                {{#ifCond readOnlyEntity "===" false}}
++                    <button class="btn btn-action btn-sm"  data-id="editAttr" data-original-title="Edit User-Defined Attributes">Edit</button>
++                {{/ifCond}}
++            </div>
++        {{/ifCond}}
++        <div id="collapse2" class="panel-collapse collapse in">
++            <div class="panel-body">
++                    <div class="row">
++                        <div class="col-md-12">
++                            <div class="entity-detail-table">
++                                <table class="table">
++                                    {{#ifCond customAttibutes.length "===" 0}}
++                                        <span>No properties have been created yet.
++                                            {{#ifCond readOnlyEntity "==" false}}
++                                                <span>To add a property, click <a href="javascript:void(0)" data-id="editAttr">here</a></span>
++                                            {{/ifCond}}
++                                        </span>
++                                    {{/ifCond}}
++                                    <tbody>
++                                        {{#each customAttibutes}}
++                                            <tr>
++                                                <td>
++                                                    <div class="scroll-y">{{key}}</div>                                              </div></td>
++                                                <td>
++                                                    <div class="scroll-y">{{value}}</div>
++                                                </td>
++                                            </tr>
++                                        {{/each}}
++                                    </tbody>
++                                </table>
++                            </div>
++                        </div>
++                    </div>
++            </div>
++        </div>
++    </div>
++</div>
+diff --git a/dashboardv2/public/js/templates/search/AdvancedSearchInfo_tmpl.html b/dashboardv2/public/js/templates/search/AdvancedSearchInfo_tmpl.html
+index 64f1a31..7746974 100644
+--- a/dashboardv2/public/js/templates/search/AdvancedSearchInfo_tmpl.html
++++ b/dashboardv2/public/js/templates/search/AdvancedSearchInfo_tmpl.html
+@@ -31,6 +31,6 @@
+         </li>
+     </ul>
+     <h5 style="padding-left: 22.5px;">
+-        <a href="http://atlas.apache.org/#/SearchAdvance" target="_blank"><i class="fa fa-info-circle" aria-hidden="true"></i> &nbsp; More sample queries and use-cases</a>
++        <a href="http://atlas.apache.org/Search-Advanced.html" target="_blank"><i class="fa fa-info-circle" aria-hidden="true"></i> &nbsp; More sample queries and use-cases</a>
+     </h5>
+ </div>
+\ No newline at end of file
+diff --git a/dashboardv2/public/js/views/detail_page/DetailPageLayoutView.js b/dashboardv2/public/js/views/detail_page/DetailPageLayoutView.js
+index 5fe5a9e..4f48693 100644
+--- a/dashboardv2/public/js/views/detail_page/DetailPageLayoutView.js
++++ b/dashboardv2/public/js/views/detail_page/DetailPageLayoutView.js
+@@ -45,7 +45,8 @@ define(['require',
+                 RAuditTableLayoutView: "#r_auditTableLayoutView",
+                 RReplicationAuditTableLayoutView: "#r_replicationAuditTableLayoutView",
+                 RProfileLayoutView: "#r_profileLayoutView",
+-                RRelationshipLayoutView: "#r_relationshipLayoutView"
++                RRelationshipLayoutView: "#r_relationshipLayoutView",
++                REntityUserDefineView: "#r_entityUserDefineView",
+             },
+             /** ui selector cache */
+             ui: {
+@@ -243,6 +244,7 @@ define(['require',
+                         })()
+                     }
+                     this.renderEntityDetailTableLayoutView(obj);
++                    this.renderEntityUserDefineView(obj);
+                     this.renderRelationshipLayoutView(obj);
+                     this.renderAuditTableLayoutView(obj);
+                     this.renderTagTableLayoutView(obj);
+@@ -484,6 +486,12 @@ define(['require',
+                     that.REntityDetailTableLayoutView.show(new EntityDetailTableLayoutView(obj));
+                 });
+             },
++            renderEntityUserDefineView: function(obj) {
++                var that = this;
++                require(['views/entity/EntityUserDefineView'], function(EntityUserDefineView) {
++                    that.REntityUserDefineView.show(new EntityUserDefineView(obj));
++                });
++            },
+             renderTagTableLayoutView: function(obj) {
+                 var that = this;
+                 require(['views/tag/TagDetailTableLayoutView'], function(TagDetailTableLayoutView) {
+@@ -545,4 +553,4 @@ define(['require',
+             }
+         });
+     return DetailPageLayoutView;
+-});
+\ No newline at end of file
++});
+diff --git a/dashboardv2/public/js/views/entity/EntityDetailTableLayoutView.js b/dashboardv2/public/js/views/entity/EntityDetailTableLayoutView.js
+index 381d99e..6572292 100644
+--- a/dashboardv2/public/js/views/entity/EntityDetailTableLayoutView.js
++++ b/dashboardv2/public/js/views/entity/EntityDetailTableLayoutView.js
+@@ -83,4 +83,4 @@ define(['require',
+             }
+         });
+     return EntityDetailTableLayoutView;
+-});
+\ No newline at end of file
++});
+diff --git a/dashboardv2/public/js/views/entity/EntityUserDefineItemView.js b/dashboardv2/public/js/views/entity/EntityUserDefineItemView.js
+new file mode 100644
+index 0000000..a649ca8
+--- /dev/null
++++ b/dashboardv2/public/js/views/entity/EntityUserDefineItemView.js
+@@ -0,0 +1,98 @@
++/*
++ * Licensed to the Apache Software Foundation (ASF) under one
++ * or more contributor license agreements.  See the NOTICE file
++ * distributed with this work for additional information
++ * regarding copyright ownership.  The ASF licenses this file
++ * to you under the Apache License, Version 2.0 (the
++ * "License"); you may not use this file except in compliance
++ * with the License.  You may obtain a copy of the License at
++ *
++ *     http://www.apache.org/licenses/LICENSE-2.0
++ *
++ * Unless required by applicable law or agreed to in writing, software
++ * distributed under the License is distributed on an "AS IS" BASIS,
++ * WITHOUT 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/entity/EntityUserDefineItemView_tmpl'
++
++], function(require, Backbone, EntityUserDefineItemView_tmpl) {
++    'use strict';
++
++    return Backbone.Marionette.ItemView.extend({
++        _viewName: 'EntityUserDefineItemView',
++
++        template: EntityUserDefineItemView_tmpl,
++
++        templateHelpers: function() {
++            return {
++                items: this.items
++            };
++        },
++
++        /** Layout sub regions */
++        regions: {},
++
++        /** ui selector cache */
++        ui: {
++            itemKey: "[data-type='key']",
++            itemValue: "[data-type='value']",
++            addItem: "[data-id='addItem']",
++            deleteItem: "[data-id='deleteItem']"
++        },
++        /** ui events hash */
++        events: function() {
++            var events = {};
++            events['input ' + this.ui.itemKey] = 'onItemKeyChange';
++            events['input ' + this.ui.itemValue] = 'onItemValueChange';
++            events['click ' + this.ui.addItem] = 'onAddItemClick';
++            events['click ' + this.ui.deleteItem] = 'onDeleteItemClick';
++            return events;
++        },
++
++        /**
++         * intialize a new GlobalExclusionComponentView Layout
++         * @constructs
++         */
++        initialize: function(options) {
++            var that = this;
++            this.editMode = options.mode;
++            if (options.items.length === 0) {
++                this.items = [{ key: "", value: "", mode: this.editMode}];
++
++            } else {
++                this.items = options.items.map(function(m) {
++                    m.mode = that.editMode;
++                    return m;
++                });
++            }
++        },
++        onRender: function() {
++
++        },
++        onAddItemClick: function(e) {
++            var el = e.currentTarget;
++            this.items.splice(parseInt(el.dataset.index) + 1, 0, { key: "", value: "", mode: this.editMode});
++            this.render();
++        },
++        onDeleteItemClick: function(e) {
++            var el = e.currentTarget;
++            this.items.splice(el.dataset.index, 1);
++            this.render();
++        },
++        onItemKeyChange: function (e) {
++            var el = e.currentTarget;
++            var val = el.value;
++            this.items[ el.dataset.index].key = val;
++        },
++        onItemValueChange: function (e) {
++            var el = e.currentTarget;
++            var val = el.value;
++            this.items[ el.dataset.index].value = el.value;
++        }
++    });
++
++});
+diff --git a/dashboardv2/public/js/views/entity/EntityUserDefineView.js b/dashboardv2/public/js/views/entity/EntityUserDefineView.js
+new file mode 100644
+index 0000000..4fc2f02
+--- /dev/null
++++ b/dashboardv2/public/js/views/entity/EntityUserDefineView.js
+@@ -0,0 +1,184 @@
++/**
++ * Licensed to the Apache Software Foundation (ASF) under one
++ * or more contributor license agreements.  See the NOTICE file
++ * distributed with this work for additional information
++ * regarding copyright ownership.  The ASF licenses this file
++ * to you under the Apache License, Version 2.0 (the
++ * "License"); you may not use this file except in compliance
++ * with the License.  You may obtain a copy of the License at
++ *
++ *     http://www.apache.org/licenses/LICENSE-2.0
++ *
++ * Unless required by applicable law or agreed to in writing, software
++ * distributed under the License is distributed on an "AS IS" BASIS,
++ * WITHOUT 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/entity/EntityUserDefineView_tmpl',
++'views/entity/EntityUserDefineItemView',
++'utils/CommonViewFunction',
++'modules/Modal',
++'models/VEntity',
++'utils/Utils',
++'utils/Enums'
++], function(require, Backbone, EntityUserDefineView_tmpl, EntityUserDefineItemView, CommonViewFunction, Modal, VEntity, Utils, Enums) {
++'use strict';
++
++    return Backbone.Marionette.LayoutView.extend({
++        _viewName: 'EntityUserDefineView',
++        template: EntityUserDefineView_tmpl,
++        templateHelpers: function() {
++            return {
++                customAttibutes: this.customAttibutes,
++                readOnlyEntity : this.readOnlyEntity
++            };
++        },
++        ui: {
++            addAttr: "[data-id='addAttr']",
++            editAttr: "[data-id='editAttr']",
++            deleteAttr: "[data-id='deleteAttr']"
++        },
++        events: function() {
++            var events = {};
++            events["click " + this.ui.editAttr] = 'onEditAttrClick';
++            return events;
++        },
++        initialize: function(options) {
++            _.extend(this, _.pick(options, 'entity'));
++            this.userDefineAttr = this.entity.customAttributes || [];
++            this.editMode = false;
++            this.readOnlyEntity = Enums.entityStateReadOnly[this.entity.status];
++            this.entityModel = new VEntity(this.entity);
++            this.generateTableFields();
++        },
++        onRender: function() {
++        },
++        bindEvents: {},
++        customAtributesFunc: function() {
++
++        },
++        generateTableFields: function() {
++            var that = this;
++            this.customAttibutes = [];
++            _.each(Object.keys(that.userDefineAttr), function(key, i) {
++                that.customAttibutes.push({
++                    key: key,
++                    value: that.userDefineAttr[key]
++                });
++            });
++        },
++        onEditAttrClick: function (e) {
++            this.editMode = true;
++            var options = {items: this.customAttibutes, mode: true};
++            var view = new EntityUserDefineItemView(options);
++            var modalObj = {
++                title: 'User-Defined Attributes',
++                content: view,
++                okText: 'Save',
++                okCloses: false,
++                cancelText: "Cancel",
++                mainClass: 'modal-lg',
++                allowCancel: true,
++            };
++           this.setAttributeModal(modalObj);
++        },
++        structureAttributes: function (list) {
++            var obj={}
++            list.map(function (o) {
++                obj[o.key] = o.value;
++            });
++            return obj;
++        },
++        saveAttributes: function (list) {
++            var that = this;
++            var entityJson = that.entityModel.toJSON();
++            var properties = that.structureAttributes(list);
++            entityJson.customAttributes = properties;
++            var payload = {entity: entityJson};
++            that.entityModel.createOreditEntity({
++                data: JSON.stringify(payload),
++                type: 'POST',
++                success: function() {
++                    var msg = "User-defined attribute(s) updated successfully";
++                    that.customAttibutes = list;
++                    Utils.notifySuccess({
++                        content: msg
++                    });
++                    that.modal && that.modal.trigger('cancel');
++                    that.render();
++                },
++                error: function (e) {
++                    that.editMode = false;
++                    Utils.notifySuccess({
++                        content: e.message
++                    });
++                    that.modal && that.modal.$el.find('button.ok').attr("disabled", false);
++                },
++                complete: function () {
++                    that.modal && that.modal.$el.find('button.ok').attr("disabled", false);
++                    that.editMode = false;
++                }
++            });
++        },
++        setAttributeModal: function(modalObj) {
++            var self = this;
++            this.modal = new Modal(modalObj);
++            this.modal.open();
++            this. modal.on('ok', function() {
++                self.modal.$el.find('button.ok').attr("disabled", true);
++                var list = self.modal.$el.find("[data-type]"),
++                    keyMap = new Map(),
++                    validation = true,
++                    hasDup = [],
++                    dataList = [];
++                Array.prototype.push.apply(dataList, self.modal.options.content.items);
++                for(var i = 0; i < list.length ; i++) {
++                    var input = list[i],
++                        type = input.dataset.type,
++                        pEl = self.modal.$el.find(input.parentElement).find('p'),
++                        classes = 'form-control',
++                        val = input.value.trim();
++                        pEl[0].innerText = "";
++
++                    if (val === '') {
++                        classes = 'form-control errorClass';
++                        validation = false;
++                        pEl[0].innerText = 'Required!';
++                    } else {
++                        if (input.tagName === 'INPUT') {
++                            var duplicates = dataList.filter(function(c) {
++                                return c.key === val;
++                            });
++                            if (keyMap.has(val) || duplicates.length > 1 ) {
++                                classes = 'form-control errorClass';
++                                hasDup.push('duplicate');
++                                pEl[0].innerText = 'Duplicate key';
++                            } else {
++                                keyMap.set(val, val);
++                            }
++                        }
++                    }
++                    input.setAttribute('class', classes);
++                }
++
++                if (validation && hasDup.length === 0) {
++                    self.saveAttributes(self.modal.options.content.items);
++                } else {
++                    self.modal.$el.find('button.ok').attr("disabled", false);
++                }
++            });
++            this.modal.on('closeModal', function() {
++                self.editMode = false;
++                self.modal.trigger('cancel');
++            });
++        },
++        enableModalButton: function () {
++            var self = this;
++            self.modal.$el.find('button.ok').attr("disabled", false);
++        }
++    });
++});
+diff --git a/dashboardv3/public/css/scss/common.scss b/dashboardv3/public/css/scss/common.scss
+index 26bf82a..dfe0e4f 100644
+--- a/dashboardv3/public/css/scss/common.scss
++++ b/dashboardv3/public/css/scss/common.scss
+@@ -201,3 +201,46 @@ pre {
+     bottom: 0;
+     background: white;
+ }
++
++.custom-table {
++    width: 100%;
++
++    .custom-tr {
++        margin-left: 15px;
++        margin-right: 15px;
++
++        .custom-col-0,
++        .custom-col-1,
++        .custom-col-2 {
++            vertical-align: top;
++            display: inline-block;
++
++            textarea {
++                resize: vertical;
++                height: 34px;
++                min-height: 34px;
++                max-height: 70px;
++            }
++        }
++
++
++        .custom-col-0{
++            text-align: center;
++            vertical-align: middle;
++            width: 2%;
++        }
++
++        .custom-col-1{
++            width: 43%;
++        }
++
++        .custom-col-2{
++            text-align: center;
++            width: 10%;
++        }
++    }
++}
++
++.errorMsg {
++    color: $red;
++}
+diff --git a/dashboardv3/public/css/scss/panel.scss b/dashboardv3/public/css/scss/panel.scss
+index dfa0872..b06e63c 100644
+--- a/dashboardv3/public/css/scss/panel.scss
++++ b/dashboardv3/public/css/scss/panel.scss
+@@ -134,4 +134,37 @@
+             }
+         }
+     }
+-}
+\ No newline at end of file
++}
++
++.panel-default.custom-panel>.panel-heading {
++    color: $black;
++    cursor: pointer;
++    border-bottom: none;
++    display: inline-block;
++
++    .panel-title {
++        font-weight: normal;
++        a:hover {
++            color: $black;
++            opacity: 0.7;
++        }
++    }
++    .btn-group {
++        margin-top: 3px;
++    }
++}
++
++.panel-default.custom-panel>.panel-actions {
++    float: right;
++    margin-top: 15px;
++    button {
++        margin-right: 10px;
++    }
++}
++
++.panel-default.custom-panel>.panel-collapse>.panel-body {
++    border-top: none;
++}
++.panel-default.custom-panel>.panel-heading > .btn-group > button {
++    color: $black;
++}
+diff --git a/dashboardv3/public/css/scss/table.scss b/dashboardv3/public/css/scss/table.scss
+index 0f8ca75..06fb29b 100644
+--- a/dashboardv3/public/css/scss/table.scss
++++ b/dashboardv3/public/css/scss/table.scss
+@@ -212,6 +212,7 @@ td {
+     pre.scroll-y {
+         max-height: 200px;
+         overflow-y: auto;
++        word-break: break-word;
+     }
+ 
+     &.searchTableName {
+diff --git a/dashboardv3/public/js/templates/detail_page/DetailPageLayoutView_tmpl.html b/dashboardv3/public/js/templates/detail_page/DetailPageLayoutView_tmpl.html
+index 6519863..9c7cb81 100644
+--- a/dashboardv3/public/js/templates/detail_page/DetailPageLayoutView_tmpl.html
++++ b/dashboardv3/public/js/templates/detail_page/DetailPageLayoutView_tmpl.html
+@@ -68,9 +68,16 @@
+ <div>
+     <div class="tab-content">
+         <div id="tab-details" role="properties" class="tab-pane active animated fadeIn">
+-            <div id="r_entityDetailTableLayoutView">
+-                <div class="fontLoader-relative">
+-                    <i class="fa fa-refresh fa-spin-custom"></i>
++            <div class="row">
++                <div class="col-md-6">
++                    <div id="r_entityDetailTableLayoutView">
++                        <div class="fontLoader-relative">
++                            <i class="fa fa-refresh fa-spin-custom"></i>
++                        </div>
++                    </div>
++                </div>
++                <div class="col-md-6">
++                    <div id="r_entityUserDefineView"></div>
+                 </div>
+             </div>
+         </div>
+@@ -125,4 +132,4 @@
+         </div>
+     </div>
+ </div>
+-</div>
+\ No newline at end of file
++</div>
+diff --git a/dashboardv3/public/js/templates/entity/EntityDetailTableLayoutView_tmpl.html b/dashboardv3/public/js/templates/entity/EntityDetailTableLayoutView_tmpl.html
+index 1c01077..18a9435 100644
+--- a/dashboardv3/public/js/templates/entity/EntityDetailTableLayoutView_tmpl.html
++++ b/dashboardv3/public/js/templates/entity/EntityDetailTableLayoutView_tmpl.html
+@@ -14,23 +14,33 @@
+  * See the License for the specific language governing permissions and
+  * limitations under the License.
+ -->
+-<div class="entity-detail-table">
+-    <div class="entity-detail-table-toggle">
+-        <div class="pretty p-switch p-fill">
+-            <input type="checkbox" data-id="noValueToggle" />
+-            <div class="state p-primary">
+-                <label>Show Empty Values</label>
++<div class="panel-group" id="accordion">
++    <div class="panel panel-default custom-panel expand_collapse_panel-icon" data-id="entity">
++        <div class="panel-heading" data-toggle="collapse" href="#collapse1" aria-expanded="true" style="width: 58%">
++            <h4 class="panel-title">
++                <a>Technical properties </a>
++            </h4>
++            <div class="btn-group pull-left">
++                <button type="button" title="Collapse"><i class="ec-icon fa"></i></button>
++            </div>
++        </div>
++        <div class="panel-actions">
++            <div class="pretty p-switch p-fill">
++                <input type="checkbox" data-id="noValueToggle" />
++                <div class="state p-primary">
++                    <label>Show Empty Values</label>
++                </div>
++            </div>
++        </div>
++        <div id="collapse1" class="panel-collapse collapse in">
++            <div class="panel-body">
++                    <div class="entity-detail-table">
++                        <table class="table">
++                            <tbody data-id="detailValue" class="hide-empty-value">
++                            </tbody>
++                        </table>
++                    </div>
+             </div>
+         </div>
+     </div>
+-    <table class="table table-quickMenu">
+-        <thead>
+-            <tr>
+-                <th>Key</th>
+-                <th>Value</th>
+-            </tr>
+-        </thead>
+-        <tbody data-id="detailValue" class="hide-empty-value">
+-        </tbody>
+-    </table>
+-</div>
+\ No newline at end of file
++</div>
+diff --git a/dashboardv3/public/js/templates/entity/EntityUserDefineItemView_tmpl.html b/dashboardv3/public/js/templates/entity/EntityUserDefineItemView_tmpl.html
+new file mode 100644
+index 0000000..a06039f
+--- /dev/null
++++ b/dashboardv3/public/js/templates/entity/EntityUserDefineItemView_tmpl.html
+@@ -0,0 +1,45 @@
++<!--
++ * Licensed to the Apache Software Foundation (ASF) under one or more
++ * contributor license agreements.  See the NOTICE file distributed with
++ * this work for additional information regarding copyright ownership.
++ * The ASF licenses this file to You under the Apache License, Version 2.0
++ * (the "License"); you may not use this file except in compliance with
++ * the License.  You may obtain a copy of the License at
++ *
++ *     http://www.apache.org/licenses/LICENSE-2.0
++ *
++ * Unless required by applicable law or agreed to in writing, software
++ * distributed under the License is distributed on an "AS IS" BASIS,
++ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
++ * See the License for the specific language governing permissions and
++ * limitations under the License.
++-->
++
++<div data-id="userDefineItems">
++    <table class="custom-table">
++        {{#each items}}
++            <tr class="custom-tr">
++                <td class="custom-col-1">
++                    <input placeholder="key" type="text"  data-type="key" data-index={{@index}} class="form-control" value={{key}}></input>
++                    <p class="errorMsg"></p>
++                </td >
++                <td  class="custom-col-0"> : </td >
++                <td  class="custom-col-1">
++                    <textarea placeholder="value"  data-type="value" data-index={{@index}} class="form-control" class="form-control">{{value}}</textarea>
++                    <p class="errorMsg"></p>
++                </td >
++                <td  class="custom-col-2">
++                    <button class="btn btn-default btn-sm" title=""  data-index={{@index}} data-id="deleteItem">
++                        <i class="fa fa-minus"> </i>
++                    </button>
++                    <button class="btn btn-default btn-sm" title="" data-index={{@index}} data-id="addItem">
++                        <i class="fa fa-plus"> </i>
++                    </button>
++                </td >
++            </tr>
++        {{/each}}
++        {{#ifCond items.length "===" 0}}
++            No properties have been created yet. To add a property, click <a href="javascript:void(0)" data-id="addItem">here</a>
++        {{/ifCond}}
++    </table>
++</div>
+diff --git a/dashboardv3/public/js/templates/entity/EntityUserDefineView_tmpl.html b/dashboardv3/public/js/templates/entity/EntityUserDefineView_tmpl.html
+new file mode 100644
+index 0000000..e3f4791
+--- /dev/null
++++ b/dashboardv3/public/js/templates/entity/EntityUserDefineView_tmpl.html
+@@ -0,0 +1,65 @@
++<!--
++ * Licensed to the Apache Software Foundation (ASF) under one or more
++ * contributor license agreements.  See the NOTICE file distributed with
++ * this work for additional information regarding copyright ownership.
++ * The ASF licenses this file to You under the Apache License, Version 2.0
++ * (the "License"); you may not use this file except in compliance with
++ * the License.  You may obtain a copy of the License at
++ *
++ *     http://www.apache.org/licenses/LICENSE-2.0
++ *
++ * Unless required by applicable law or agreed to in writing, software
++ * distributed under the License is distributed on an "AS IS" BASIS,
++ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
++ * See the License for the specific language governing permissions and
++ * limitations under the License.
++-->
++<div class="panel-group" id="accordion">
++    <div class="panel panel-default custom-panel expand_collapse_panel-icon" data-id="userDefine">
++        <div class="panel-heading" data-toggle="collapse" href="#collapse2" aria-expanded="true" {{#ifCond customAttibutes.length ">" 0}} style="width: 60%" {{else}} style="width: 100%" {{/ifCond}}>
++            <h4 class="panel-title">
++                <a>User-defined properties </a>
++            </h4>
++            <div class="btn-group pull-left">
++                <button type="button" title="Collapse"><i class="ec-icon fa"></i></button>
++            </div>
++        </div>
++        {{#ifCond customAttibutes.length ">" 0}}
++            <div class="panel-actions">
++                {{#ifCond readOnlyEntity "===" false}}
++                    <button class="btn btn-action btn-sm"  data-id="editAttr" data-original-title="Edit User-Defined Attributes">Edit</button>
++                {{/ifCond}}
++            </div>
++        {{/ifCond}}
++        <div id="collapse2" class="panel-collapse collapse in">
++            <div class="panel-body">
++                    <div class="row">
++                        <div class="col-md-12">
++                            <div class="entity-detail-table">
++                                <table class="table">
++                                    {{#ifCond customAttibutes.length "===" 0}}
++                                        <span>No properties have been created yet.
++                                            {{#ifCond readOnlyEntity "==" false}}
++                                                <span>To add a property, click <a href="javascript:void(0)" data-id="editAttr">here</a></span>
++                                            {{/ifCond}}
++                                        </span>
++                                    {{/ifCond}}
++                                    <tbody>
++                                        {{#each customAttibutes}}
++                                            <tr>
++                                                <td>
++                                                    <div class="scroll-y">{{key}}</div>                                              </div></td>
++                                                <td>
++                                                    <div class="scroll-y">{{value}}</div>
++                                                </td>
++                                            </tr>
++                                        {{/each}}
++                                    </tbody>
++                                </table>
++                            </div>
++                        </div>
++                    </div>
++            </div>
++        </div>
++    </div>
++</div>
+diff --git a/dashboardv3/public/js/views/detail_page/DetailPageLayoutView.js b/dashboardv3/public/js/views/detail_page/DetailPageLayoutView.js
+index 682feb3..e1ab970 100644
+--- a/dashboardv3/public/js/views/detail_page/DetailPageLayoutView.js
++++ b/dashboardv3/public/js/views/detail_page/DetailPageLayoutView.js
+@@ -45,7 +45,8 @@ define(['require',
+                 RAuditTableLayoutView: "#r_auditTableLayoutView",
+                 RReplicationAuditTableLayoutView: "#r_replicationAuditTableLayoutView",
+                 RProfileLayoutView: "#r_profileLayoutView",
+-                RRelationshipLayoutView: "#r_relationshipLayoutView"
++                RRelationshipLayoutView: "#r_relationshipLayoutView",
++                REntityUserDefineView: "#r_entityUserDefineView",
+             },
+             /** ui selector cache */
+             ui: {
+@@ -249,6 +250,7 @@ define(['require',
+                         })()
+                     }
+                     this.renderEntityDetailTableLayoutView(obj);
++                    this.renderEntityUserDefineView(obj);
+                     this.renderRelationshipLayoutView(obj);
+                     this.renderAuditTableLayoutView(obj);
+                     this.renderTagTableLayoutView(obj);
+@@ -496,6 +498,12 @@ define(['require',
+                     that.REntityDetailTableLayoutView.show(new EntityDetailTableLayoutView(obj));
+                 });
+             },
++            renderEntityUserDefineView: function(obj) {
++                var that = this;
++                require(['views/entity/EntityUserDefineView'], function(EntityUserDefineView) {
++                    that.REntityUserDefineView.show(new EntityUserDefineView(obj));
++                });
++            },
+             renderTagTableLayoutView: function(obj) {
+                 var that = this;
+                 require(['views/tag/TagDetailTableLayoutView'], function(TagDetailTableLayoutView) {
+@@ -558,4 +566,4 @@ define(['require',
+             }
+         });
+     return DetailPageLayoutView;
+-});
+\ No newline at end of file
++});
+diff --git a/dashboardv3/public/js/views/entity/EntityDetailTableLayoutView.js b/dashboardv3/public/js/views/entity/EntityDetailTableLayoutView.js
+index 381d99e..6572292 100644
+--- a/dashboardv3/public/js/views/entity/EntityDetailTableLayoutView.js
++++ b/dashboardv3/public/js/views/entity/EntityDetailTableLayoutView.js
+@@ -83,4 +83,4 @@ define(['require',
+             }
+         });
+     return EntityDetailTableLayoutView;
+-});
+\ No newline at end of file
++});
+diff --git a/dashboardv3/public/js/views/entity/EntityUserDefineItemView.js b/dashboardv3/public/js/views/entity/EntityUserDefineItemView.js
+new file mode 100644
+index 0000000..a649ca8
+--- /dev/null
++++ b/dashboardv3/public/js/views/entity/EntityUserDefineItemView.js
+@@ -0,0 +1,98 @@
++/*
++ * Licensed to the Apache Software Foundation (ASF) under one
++ * or more contributor license agreements.  See the NOTICE file
++ * distributed with this work for additional information
++ * regarding copyright ownership.  The ASF licenses this file
++ * to you under the Apache License, Version 2.0 (the
++ * "License"); you may not use this file except in compliance
++ * with the License.  You may obtain a copy of the License at
++ *
++ *     http://www.apache.org/licenses/LICENSE-2.0
++ *
++ * Unless required by applicable law or agreed to in writing, software
++ * distributed under the License is distributed on an "AS IS" BASIS,
++ * WITHOUT 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/entity/EntityUserDefineItemView_tmpl'
++
++], function(require, Backbone, EntityUserDefineItemView_tmpl) {
++    'use strict';
++
++    return Backbone.Marionette.ItemView.extend({
++        _viewName: 'EntityUserDefineItemView',
++
++        template: EntityUserDefineItemView_tmpl,
++
++        templateHelpers: function() {
++            return {
++                items: this.items
++            };
++        },
++
++        /** Layout sub regions */
++        regions: {},
++
++        /** ui selector cache */
++        ui: {
++            itemKey: "[data-type='key']",
++            itemValue: "[data-type='value']",
++            addItem: "[data-id='addItem']",
++            deleteItem: "[data-id='deleteItem']"
++        },
++        /** ui events hash */
++        events: function() {
++            var events = {};
++            events['input ' + this.ui.itemKey] = 'onItemKeyChange';
++            events['input ' + this.ui.itemValue] = 'onItemValueChange';
++            events['click ' + this.ui.addItem] = 'onAddItemClick';
++            events['click ' + this.ui.deleteItem] = 'onDeleteItemClick';
++            return events;
++        },
++
++        /**
++         * intialize a new GlobalExclusionComponentView Layout
++         * @constructs
++         */
++        initialize: function(options) {
++            var that = this;
++            this.editMode = options.mode;
++            if (options.items.length === 0) {
++                this.items = [{ key: "", value: "", mode: this.editMode}];
++
++            } else {
++                this.items = options.items.map(function(m) {
++                    m.mode = that.editMode;
++                    return m;
++                });
++            }
++        },
++        onRender: function() {
++
++        },
++        onAddItemClick: function(e) {
++            var el = e.currentTarget;
++            this.items.splice(parseInt(el.dataset.index) + 1, 0, { key: "", value: "", mode: this.editMode});
++            this.render();
++        },
++        onDeleteItemClick: function(e) {
++            var el = e.currentTarget;
++            this.items.splice(el.dataset.index, 1);
++            this.render();
++        },
++        onItemKeyChange: function (e) {
++            var el = e.currentTarget;
++            var val = el.value;
++            this.items[ el.dataset.index].key = val;
++        },
++        onItemValueChange: function (e) {
++            var el = e.currentTarget;
++            var val = el.value;
++            this.items[ el.dataset.index].value = el.value;
++        }
++    });
++
++});
+diff --git a/dashboardv3/public/js/views/entity/EntityUserDefineView.js b/dashboardv3/public/js/views/entity/EntityUserDefineView.js
+new file mode 100644
+index 0000000..4fc2f02
+--- /dev/null
++++ b/dashboardv3/public/js/views/entity/EntityUserDefineView.js
+@@ -0,0 +1,184 @@
++/**
++ * Licensed to the Apache Software Foundation (ASF) under one
++ * or more contributor license agreements.  See the NOTICE file
++ * distributed with this work for additional information
++ * regarding copyright ownership.  The ASF licenses this file
++ * to you under the Apache License, Version 2.0 (the
++ * "License"); you may not use this file except in compliance
++ * with the License.  You may obtain a copy of the License at
++ *
++ *     http://www.apache.org/licenses/LICENSE-2.0
++ *
++ * Unless required by applicable law or agreed to in writing, software
++ * distributed under the License is distributed on an "AS IS" BASIS,
++ * WITHOUT 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/entity/EntityUserDefineView_tmpl',
++'views/entity/EntityUserDefineItemView',
++'utils/CommonViewFunction',
++'modules/Modal',
++'models/VEntity',
++'utils/Utils',
++'utils/Enums'
++], function(require, Backbone, EntityUserDefineView_tmpl, EntityUserDefineItemView, CommonViewFunction, Modal, VEntity, Utils, Enums) {
++'use strict';
++
++    return Backbone.Marionette.LayoutView.extend({
++        _viewName: 'EntityUserDefineView',
++        template: EntityUserDefineView_tmpl,
++        templateHelpers: function() {
++            return {
++                customAttibutes: this.customAttibutes,
++                readOnlyEntity : this.readOnlyEntity
++            };
++        },
++        ui: {
++            addAttr: "[data-id='addAttr']",
++            editAttr: "[data-id='editAttr']",
++            deleteAttr: "[data-id='deleteAttr']"
++        },
++        events: function() {
++            var events = {};
++            events["click " + this.ui.editAttr] = 'onEditAttrClick';
++            return events;
++        },
++        initialize: function(options) {
++            _.extend(this, _.pick(options, 'entity'));
++            this.userDefineAttr = this.entity.customAttributes || [];
++            this.editMode = false;
++            this.readOnlyEntity = Enums.entityStateReadOnly[this.entity.status];
++            this.entityModel = new VEntity(this.entity);
++            this.generateTableFields();
++        },
++        onRender: function() {
++        },
++        bindEvents: {},
++        customAtributesFunc: function() {
++
++        },
++        generateTableFields: function() {
++            var that = this;
++            this.customAttibutes = [];
++            _.each(Object.keys(that.userDefineAttr), function(key, i) {
++                that.customAttibutes.push({
++                    key: key,
++                    value: that.userDefineAttr[key]
++                });
++            });
++        },
++        onEditAttrClick: function (e) {
++            this.editMode = true;
++            var options = {items: this.customAttibutes, mode: true};
++            var view = new EntityUserDefineItemView(options);
++            var modalObj = {
++                title: 'User-Defined Attributes',
++                content: view,
++                okText: 'Save',
++                okCloses: false,
++                cancelText: "Cancel",
++                mainClass: 'modal-lg',
++                allowCancel: true,
++            };
++           this.setAttributeModal(modalObj);
++        },
++        structureAttributes: function (list) {
++            var obj={}
++            list.map(function (o) {
++                obj[o.key] = o.value;
++            });
++            return obj;
++        },
++        saveAttributes: function (list) {
++            var that = this;
++            var entityJson = that.entityModel.toJSON();
++            var properties = that.structureAttributes(list);
++            entityJson.customAttributes = properties;
++            var payload = {entity: entityJson};
++            that.entityModel.createOreditEntity({
++                data: JSON.stringify(payload),
++                type: 'POST',
++                success: function() {
++                    var msg = "User-defined attribute(s) updated successfully";
++                    that.customAttibutes = list;
++                    Utils.notifySuccess({
++                        content: msg
++                    });
++                    that.modal && that.modal.trigger('cancel');
++                    that.render();
++                },
++                error: function (e) {
++                    that.editMode = false;
++                    Utils.notifySuccess({
++                        content: e.message
++                    });
++                    that.modal && that.modal.$el.find('button.ok').attr("disabled", false);
++                },
++                complete: function () {
++                    that.modal && that.modal.$el.find('button.ok').attr("disabled", false);
++                    that.editMode = false;
++                }
++            });
++        },
++        setAttributeModal: function(modalObj) {
++            var self = this;
++            this.modal = new Modal(modalObj);
++            this.modal.open();
++            this. modal.on('ok', function() {
++                self.modal.$el.find('button.ok').attr("disabled", true);
++                var list = self.modal.$el.find("[data-type]"),
++                    keyMap = new Map(),
++                    validation = true,
++                    hasDup = [],
++                    dataList = [];
++                Array.prototype.push.apply(dataList, self.modal.options.content.items);
++                for(var i = 0; i < list.length ; i++) {
++                    var input = list[i],
++                        type = input.dataset.type,
++                        pEl = self.modal.$el.find(input.parentElement).find('p'),
++                        classes = 'form-control',
++                        val = input.value.trim();
++                        pEl[0].innerText = "";
++
++                    if (val === '') {
++                        classes = 'form-control errorClass';
++                        validation = false;
++                        pEl[0].innerText = 'Required!';
++                    } else {
++                        if (input.tagName === 'INPUT') {
++                            var duplicates = dataList.filter(function(c) {
++                                return c.key === val;
++                            });
++                            if (keyMap.has(val) || duplicates.length > 1 ) {
++                                classes = 'form-control errorClass';
++                                hasDup.push('duplicate');
++                                pEl[0].innerText = 'Duplicate key';
++                            } else {
++                                keyMap.set(val, val);
++                            }
++                        }
++                    }
++                    input.setAttribute('class', classes);
++                }
++
++                if (validation && hasDup.length === 0) {
++                    self.saveAttributes(self.modal.options.content.items);
++                } else {
++                    self.modal.$el.find('button.ok').attr("disabled", false);
++                }
++            });
++            this.modal.on('closeModal', function() {
++                self.editMode = false;
++                self.modal.trigger('cancel');
++            });
++        },
++        enableModalButton: function () {
++            var self = this;
++            self.modal.$el.find('button.ok').attr("disabled", false);
++        }
++    });
++});
+-- 
+2.7.4
+
diff --git a/dashboardv2/public/css/scss/common.scss b/dashboardv2/public/css/scss/common.scss
index d42e5a9..b24c3c3 100644
--- a/dashboardv2/public/css/scss/common.scss
+++ b/dashboardv2/public/css/scss/common.scss
@@ -15,7 +15,7 @@
 // limitations under the License.
 
 
-/* common.scss */ 
+/* common.scss */
 
 .readOnly {
 
@@ -201,4 +201,47 @@ pre {
     .panel-default>.panel-heading {
         cursor: pointer;
     }
-}
\ No newline at end of file
+}
+
+.custom-table {
+    width: 100%;
+
+    .custom-tr {
+        margin-left: 15px;
+        margin-right: 15px;
+
+        .custom-col-0,
+        .custom-col-1,
+        .custom-col-2 {
+            vertical-align: top;
+            display: inline-block;
+
+            textarea {
+                resize: vertical;
+                height: 34px;
+                min-height: 34px;
+                max-height: 70px;
+            }
+        }
+
+
+        .custom-col-0{
+            text-align: center;
+            vertical-align: middle;
+            width: 2%;
+        }
+
+        .custom-col-1{
+            width: 43%;
+        }
+
+        .custom-col-2{
+            text-align: center;
+            width: 10%;
+        }
+    }
+}
+
+.errorMsg {
+    color: $red;
+}
diff --git a/dashboardv2/public/css/scss/override.scss b/dashboardv2/public/css/scss/override.scss
index c8a1d89..c95ee58 100644
--- a/dashboardv2/public/css/scss/override.scss
+++ b/dashboardv2/public/css/scss/override.scss
@@ -128,6 +128,7 @@ td {
     pre.scroll-y {
         max-height: 200px;
         overflow-y: auto;
+        word-break: break-word;
     }
 }
 
@@ -469,4 +470,4 @@ div.columnmanager-dropdown-container {
 
 .w30 {
     width: 30% !important;
-}
\ No newline at end of file
+}
diff --git a/dashboardv2/public/css/scss/panel.scss b/dashboardv2/public/css/scss/panel.scss
index c1ac042..e6dd4bb 100644
--- a/dashboardv2/public/css/scss/panel.scss
+++ b/dashboardv2/public/css/scss/panel.scss
@@ -118,4 +118,38 @@
             }
         }
     }
-}
\ No newline at end of file
+}
+
+.panel-default.custom-panel>.panel-heading {
+    color: $black;
+    cursor: pointer;
+    border-bottom: none;
+    display: inline-block;
+
+    .panel-title {
+        font-weight: normal;
+        a:hover {
+            color: $black;
+            opacity: 0.7;
+        }
+    }
+    .btn-group {
+        margin-top: 3px;
+    }
+}
+
+.panel-default.custom-panel>.panel-actions {
+    float: right;
+    margin-top: 15px;
+    button {
+        margin-right: 10px;
+        margin-top: -4px;
+    }
+}
+
+.panel-default.custom-panel>.panel-collapse>.panel-body {
+    border-top: none;
+}
+.panel-default.custom-panel>.panel-heading > .btn-group > button {
+    color: $black;
+}
diff --git a/dashboardv2/public/js/templates/detail_page/DetailPageLayoutView_tmpl.html b/dashboardv2/public/js/templates/detail_page/DetailPageLayoutView_tmpl.html
index c395799..d35debc 100644
--- a/dashboardv2/public/js/templates/detail_page/DetailPageLayoutView_tmpl.html
+++ b/dashboardv2/public/js/templates/detail_page/DetailPageLayoutView_tmpl.html
@@ -65,9 +65,16 @@
 <div>
     <div class="tab-content">
         <div id="tab-details" role="properties" class="tab-pane active animated fadeIn">
-            <div id="r_entityDetailTableLayoutView">
-                <div class="fontLoader-relative">
-                    <i class="fa fa-refresh fa-spin-custom"></i>
+            <div class="row">
+                <div class="col-md-6">
+                    <div id="r_entityDetailTableLayoutView">
+                        <div class="fontLoader-relative">
+                            <i class="fa fa-refresh fa-spin-custom"></i>
+                        </div>
+                    </div>
+                </div>
+                <div class="col-md-6">
+                    <div id="r_entityUserDefineView"></div>
                 </div>
             </div>
         </div>
@@ -122,4 +129,4 @@
         </div>
     </div>
 </div>
-</div>
\ No newline at end of file
+</div>
diff --git a/dashboardv2/public/js/templates/entity/EntityDetailTableLayoutView_tmpl.html b/dashboardv2/public/js/templates/entity/EntityDetailTableLayoutView_tmpl.html
index 1c01077..18a9435 100644
--- a/dashboardv2/public/js/templates/entity/EntityDetailTableLayoutView_tmpl.html
+++ b/dashboardv2/public/js/templates/entity/EntityDetailTableLayoutView_tmpl.html
@@ -14,23 +14,33 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
 -->
-<div class="entity-detail-table">
-    <div class="entity-detail-table-toggle">
-        <div class="pretty p-switch p-fill">
-            <input type="checkbox" data-id="noValueToggle" />
-            <div class="state p-primary">
-                <label>Show Empty Values</label>
+<div class="panel-group" id="accordion">
+    <div class="panel panel-default custom-panel expand_collapse_panel-icon" data-id="entity">
+        <div class="panel-heading" data-toggle="collapse" href="#collapse1" aria-expanded="true" style="width: 58%">
+            <h4 class="panel-title">
+                <a>Technical properties </a>
+            </h4>
+            <div class="btn-group pull-left">
+                <button type="button" title="Collapse"><i class="ec-icon fa"></i></button>
+            </div>
+        </div>
+        <div class="panel-actions">
+            <div class="pretty p-switch p-fill">
+                <input type="checkbox" data-id="noValueToggle" />
+                <div class="state p-primary">
+                    <label>Show Empty Values</label>
+                </div>
+            </div>
+        </div>
+        <div id="collapse1" class="panel-collapse collapse in">
+            <div class="panel-body">
+                    <div class="entity-detail-table">
+                        <table class="table">
+                            <tbody data-id="detailValue" class="hide-empty-value">
+                            </tbody>
+                        </table>
+                    </div>
             </div>
         </div>
     </div>
-    <table class="table table-quickMenu">
-        <thead>
-            <tr>
-                <th>Key</th>
-                <th>Value</th>
-            </tr>
-        </thead>
-        <tbody data-id="detailValue" class="hide-empty-value">
-        </tbody>
-    </table>
-</div>
\ No newline at end of file
+</div>
diff --git a/dashboardv2/public/js/templates/entity/EntityUserDefineItemView_tmpl.html b/dashboardv2/public/js/templates/entity/EntityUserDefineItemView_tmpl.html
new file mode 100644
index 0000000..a06039f
--- /dev/null
+++ b/dashboardv2/public/js/templates/entity/EntityUserDefineItemView_tmpl.html
@@ -0,0 +1,45 @@
+<!--
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+-->
+
+<div data-id="userDefineItems">
+    <table class="custom-table">
+        {{#each items}}
+            <tr class="custom-tr">
+                <td class="custom-col-1">
+                    <input placeholder="key" type="text"  data-type="key" data-index={{@index}} class="form-control" value={{key}}></input>
+                    <p class="errorMsg"></p>
+                </td >
+                <td  class="custom-col-0"> : </td >
+                <td  class="custom-col-1">
+                    <textarea placeholder="value"  data-type="value" data-index={{@index}} class="form-control" class="form-control">{{value}}</textarea>
+                    <p class="errorMsg"></p>
+                </td >
+                <td  class="custom-col-2">
+                    <button class="btn btn-default btn-sm" title=""  data-index={{@index}} data-id="deleteItem">
+                        <i class="fa fa-minus"> </i>
+                    </button>
+                    <button class="btn btn-default btn-sm" title="" data-index={{@index}} data-id="addItem">
+                        <i class="fa fa-plus"> </i>
+                    </button>
+                </td >
+            </tr>
+        {{/each}}
+        {{#ifCond items.length "===" 0}}
+            No properties have been created yet. To add a property, click <a href="javascript:void(0)" data-id="addItem">here</a>
+        {{/ifCond}}
+    </table>
+</div>
diff --git a/dashboardv2/public/js/templates/entity/EntityUserDefineView_tmpl.html b/dashboardv2/public/js/templates/entity/EntityUserDefineView_tmpl.html
new file mode 100644
index 0000000..4f704a5
--- /dev/null
+++ b/dashboardv2/public/js/templates/entity/EntityUserDefineView_tmpl.html
@@ -0,0 +1,73 @@
+<!--
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+-->
+<div class="panel-group" id="accordion">
+    <div class="panel panel-default custom-panel expand_collapse_panel-icon" data-id="userDefine">
+        {{#ifCond customAttibutes.length "===" 0}}
+            <div class="panel-heading collapsed" data-toggle="collapse" href="#collapse2" aria-expanded="false" style="width: 70%">
+                <h4 class="panel-title">
+                    <a>User-defined properties </a>
+                </h4>
+                <div class="btn-group pull-left">
+                    <button type="button" title="Collapse"><i class="ec-icon fa"></i></button>
+                </div>
+            </div>
+            <div class="panel-actions">
+                {{#ifCond readOnlyEntity "===" false}}
+                    <button class="btn btn-action btn-sm"  data-id="editAttr" data-original-title="Add User-Defined"> Add</button>
+                {{/ifCond}}
+            </div>
+        {{else}}
+            <div class="panel-heading" data-toggle="collapse" href="#collapse2" aria-expanded="true" style="width: 60%">
+                <h4 class="panel-title">
+                    <a>User-defined properties </a>
+                </h4>
+                <div class="btn-group pull-left">
+                    <button type="button" title="Collapse"><i class="ec-icon fa"></i></button>
+                </div>
+            </div>
+            <div class="panel-actions">
+                {{#ifCond readOnlyEntity "===" false}}
+                    <button class="btn btn-action btn-sm"  data-id="editAttr" data-original-title="Edit User-Defined Attributes">Edit</button>
+                {{/ifCond}}
+            </div>
+        {{/ifCond}}
+
+        <div id="collapse2" {{#ifCond customAttibutes.length "===" 0}} class="panel-collapse collapse" {{else}} class="panel-collapse collapse in" {{/ifCond}} >
+            <div class="panel-body">
+                    <div class="row">
+                        <div class="col-md-12">
+                            <div class="entity-detail-table">
+                                <table class="table">
+                                    <tbody>
+                                        {{#each customAttibutes}}
+                                            <tr>
+                                                <td>
+                                                    <div class="scroll-y">{{key}}</div>                                              </div></td>
+                                                <td>
+                                                    <div class="scroll-y">{{value}}</div>
+                                                </td>
+                                            </tr>
+                                        {{/each}}
+                                    </tbody>
+                                </table>
+                            </div>
+                        </div>
+                    </div>
+            </div>
+        </div>
+    </div>
+</div>
diff --git a/dashboardv2/public/js/views/detail_page/DetailPageLayoutView.js b/dashboardv2/public/js/views/detail_page/DetailPageLayoutView.js
index 5fe5a9e..4f48693 100644
--- a/dashboardv2/public/js/views/detail_page/DetailPageLayoutView.js
+++ b/dashboardv2/public/js/views/detail_page/DetailPageLayoutView.js
@@ -45,7 +45,8 @@ define(['require',
                 RAuditTableLayoutView: "#r_auditTableLayoutView",
                 RReplicationAuditTableLayoutView: "#r_replicationAuditTableLayoutView",
                 RProfileLayoutView: "#r_profileLayoutView",
-                RRelationshipLayoutView: "#r_relationshipLayoutView"
+                RRelationshipLayoutView: "#r_relationshipLayoutView",
+                REntityUserDefineView: "#r_entityUserDefineView",
             },
             /** ui selector cache */
             ui: {
@@ -243,6 +244,7 @@ define(['require',
                         })()
                     }
                     this.renderEntityDetailTableLayoutView(obj);
+                    this.renderEntityUserDefineView(obj);
                     this.renderRelationshipLayoutView(obj);
                     this.renderAuditTableLayoutView(obj);
                     this.renderTagTableLayoutView(obj);
@@ -484,6 +486,12 @@ define(['require',
                     that.REntityDetailTableLayoutView.show(new EntityDetailTableLayoutView(obj));
                 });
             },
+            renderEntityUserDefineView: function(obj) {
+                var that = this;
+                require(['views/entity/EntityUserDefineView'], function(EntityUserDefineView) {
+                    that.REntityUserDefineView.show(new EntityUserDefineView(obj));
+                });
+            },
             renderTagTableLayoutView: function(obj) {
                 var that = this;
                 require(['views/tag/TagDetailTableLayoutView'], function(TagDetailTableLayoutView) {
@@ -545,4 +553,4 @@ define(['require',
             }
         });
     return DetailPageLayoutView;
-});
\ No newline at end of file
+});
diff --git a/dashboardv2/public/js/views/entity/EntityDetailTableLayoutView.js b/dashboardv2/public/js/views/entity/EntityDetailTableLayoutView.js
index 381d99e..6572292 100644
--- a/dashboardv2/public/js/views/entity/EntityDetailTableLayoutView.js
+++ b/dashboardv2/public/js/views/entity/EntityDetailTableLayoutView.js
@@ -83,4 +83,4 @@ define(['require',
             }
         });
     return EntityDetailTableLayoutView;
-});
\ No newline at end of file
+});
diff --git a/dashboardv2/public/js/views/entity/EntityUserDefineItemView.js b/dashboardv2/public/js/views/entity/EntityUserDefineItemView.js
new file mode 100644
index 0000000..a649ca8
--- /dev/null
+++ b/dashboardv2/public/js/views/entity/EntityUserDefineItemView.js
@@ -0,0 +1,98 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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/entity/EntityUserDefineItemView_tmpl'
+
+], function(require, Backbone, EntityUserDefineItemView_tmpl) {
+    'use strict';
+
+    return Backbone.Marionette.ItemView.extend({
+        _viewName: 'EntityUserDefineItemView',
+
+        template: EntityUserDefineItemView_tmpl,
+
+        templateHelpers: function() {
+            return {
+                items: this.items
+            };
+        },
+
+        /** Layout sub regions */
+        regions: {},
+
+        /** ui selector cache */
+        ui: {
+            itemKey: "[data-type='key']",
+            itemValue: "[data-type='value']",
+            addItem: "[data-id='addItem']",
+            deleteItem: "[data-id='deleteItem']"
+        },
+        /** ui events hash */
+        events: function() {
+            var events = {};
+            events['input ' + this.ui.itemKey] = 'onItemKeyChange';
+            events['input ' + this.ui.itemValue] = 'onItemValueChange';
+            events['click ' + this.ui.addItem] = 'onAddItemClick';
+            events['click ' + this.ui.deleteItem] = 'onDeleteItemClick';
+            return events;
+        },
+
+        /**
+         * intialize a new GlobalExclusionComponentView Layout
+         * @constructs
+         */
+        initialize: function(options) {
+            var that = this;
+            this.editMode = options.mode;
+            if (options.items.length === 0) {
+                this.items = [{ key: "", value: "", mode: this.editMode}];
+
+            } else {
+                this.items = options.items.map(function(m) {
+                    m.mode = that.editMode;
+                    return m;
+                });
+            }
+        },
+        onRender: function() {
+
+        },
+        onAddItemClick: function(e) {
+            var el = e.currentTarget;
+            this.items.splice(parseInt(el.dataset.index) + 1, 0, { key: "", value: "", mode: this.editMode});
+            this.render();
+        },
+        onDeleteItemClick: function(e) {
+            var el = e.currentTarget;
+            this.items.splice(el.dataset.index, 1);
+            this.render();
+        },
+        onItemKeyChange: function (e) {
+            var el = e.currentTarget;
+            var val = el.value;
+            this.items[ el.dataset.index].key = val;
+        },
+        onItemValueChange: function (e) {
+            var el = e.currentTarget;
+            var val = el.value;
+            this.items[ el.dataset.index].value = el.value;
+        }
+    });
+
+});
diff --git a/dashboardv2/public/js/views/entity/EntityUserDefineView.js b/dashboardv2/public/js/views/entity/EntityUserDefineView.js
new file mode 100644
index 0000000..588703f
--- /dev/null
+++ b/dashboardv2/public/js/views/entity/EntityUserDefineView.js
@@ -0,0 +1,184 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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/entity/EntityUserDefineView_tmpl',
+'views/entity/EntityUserDefineItemView',
+'utils/CommonViewFunction',
+'modules/Modal',
+'models/VEntity',
+'utils/Utils',
+'utils/Enums'
+], function(require, Backbone, EntityUserDefineView_tmpl, EntityUserDefineItemView, CommonViewFunction, Modal, VEntity, Utils, Enums) {
+'use strict';
+
+    return Backbone.Marionette.LayoutView.extend({
+        _viewName: 'EntityUserDefineView',
+        template: EntityUserDefineView_tmpl,
+        templateHelpers: function() {
+            return {
+                customAttibutes: this.customAttibutes,
+                readOnlyEntity : this.readOnlyEntity
+            };
+        },
+        ui: {
+            addAttr: "[data-id='addAttr']",
+            editAttr: "[data-id='editAttr']",
+            deleteAttr: "[data-id='deleteAttr']"
+        },
+        events: function() {
+            var events = {};
+            events["click " + this.ui.editAttr] = 'onEditAttrClick';
+            return events;
+        },
+        initialize: function(options) {
+            _.extend(this, _.pick(options, 'entity'));
+            this.userDefineAttr = this.entity.customAttributes || [];
+            this.editMode = false;
+            this.readOnlyEntity = Enums.entityStateReadOnly[this.entity.status];
+            this.entityModel = new VEntity(this.entity);
+            this.generateTableFields();
+        },
+        onRender: function() {
+        },
+        bindEvents: {},
+        customAtributesFunc: function() {
+
+        },
+        generateTableFields: function() {
+            var that = this;
+            this.customAttibutes = [];
+            _.each(Object.keys(that.userDefineAttr), function(key, i) {
+                that.customAttibutes.push({
+                    key: key,
+                    value: that.userDefineAttr[key]
+                });
+            });
+        },
+        onEditAttrClick: function (e) {
+            this.editMode = true;
+            var options = {items: this.customAttibutes, mode: true};
+            var view = new EntityUserDefineItemView(options);
+            var modalObj = {
+                title: 'User-defined properties',
+                content: view,
+                okText: 'Save',
+                okCloses: false,
+                cancelText: "Cancel",
+                mainClass: 'modal-lg',
+                allowCancel: true,
+            };
+           this.setAttributeModal(modalObj);
+        },
+        structureAttributes: function (list) {
+            var obj={}
+            list.map(function (o) {
+                obj[o.key] = o.value;
+            });
+            return obj;
+        },
+        saveAttributes: function (list) {
+            var that = this;
+            var entityJson = that.entityModel.toJSON();
+            var properties = that.structureAttributes(list);
+            entityJson.customAttributes = properties;
+            var payload = {entity: entityJson};
+            that.entityModel.createOreditEntity({
+                data: JSON.stringify(payload),
+                type: 'POST',
+                success: function() {
+                    var msg = "User-defined properties updated successfully";
+                    that.customAttibutes = list;
+                    Utils.notifySuccess({
+                        content: msg
+                    });
+                    that.modal && that.modal.trigger('cancel');
+                    that.render();
+                },
+                error: function (e) {
+                    that.editMode = false;
+                    Utils.notifySuccess({
+                        content: e.message
+                    });
+                    that.modal && that.modal.$el.find('button.ok').attr("disabled", false);
+                },
+                complete: function () {
+                    that.modal && that.modal.$el.find('button.ok').attr("disabled", false);
+                    that.editMode = false;
+                }
+            });
+        },
+        setAttributeModal: function(modalObj) {
+            var self = this;
+            this.modal = new Modal(modalObj);
+            this.modal.open();
+            this. modal.on('ok', function() {
+                self.modal.$el.find('button.ok').attr("disabled", true);
+                var list = self.modal.$el.find("[data-type]"),
+                    keyMap = new Map(),
+                    validation = true,
+                    hasDup = [],
+                    dataList = [];
+                Array.prototype.push.apply(dataList, self.modal.options.content.items);
+                for(var i = 0; i < list.length ; i++) {
+                    var input = list[i],
+                        type = input.dataset.type,
+                        pEl = self.modal.$el.find(input.parentElement).find('p'),
+                        classes = 'form-control',
+                        val = input.value.trim();
+                        pEl[0].innerText = "";
+
+                    if (val === '') {
+                        classes = 'form-control errorClass';
+                        validation = false;
+                        pEl[0].innerText = 'Required!';
+                    } else {
+                        if (input.tagName === 'INPUT') {
+                            var duplicates = dataList.filter(function(c) {
+                                return c.key === val;
+                            });
+                            if (keyMap.has(val) || duplicates.length > 1 ) {
+                                classes = 'form-control errorClass';
+                                hasDup.push('duplicate');
+                                pEl[0].innerText = 'Duplicate key';
+                            } else {
+                                keyMap.set(val, val);
+                            }
+                        }
+                    }
+                    input.setAttribute('class', classes);
+                }
+
+                if (validation && hasDup.length === 0) {
+                    self.saveAttributes(self.modal.options.content.items);
+                } else {
+                    self.modal.$el.find('button.ok').attr("disabled", false);
+                }
+            });
+            this.modal.on('closeModal', function() {
+                self.editMode = false;
+                self.modal.trigger('cancel');
+            });
+        },
+        enableModalButton: function () {
+            var self = this;
+            self.modal.$el.find('button.ok').attr("disabled", false);
+        }
+    });
+});
diff --git a/dashboardv3/public/css/scss/common.scss b/dashboardv3/public/css/scss/common.scss
index 26bf82a..dfe0e4f 100644
--- a/dashboardv3/public/css/scss/common.scss
+++ b/dashboardv3/public/css/scss/common.scss
@@ -201,3 +201,46 @@ pre {
     bottom: 0;
     background: white;
 }
+
+.custom-table {
+    width: 100%;
+
+    .custom-tr {
+        margin-left: 15px;
+        margin-right: 15px;
+
+        .custom-col-0,
+        .custom-col-1,
+        .custom-col-2 {
+            vertical-align: top;
+            display: inline-block;
+
+            textarea {
+                resize: vertical;
+                height: 34px;
+                min-height: 34px;
+                max-height: 70px;
+            }
+        }
+
+
+        .custom-col-0{
+            text-align: center;
+            vertical-align: middle;
+            width: 2%;
+        }
+
+        .custom-col-1{
+            width: 43%;
+        }
+
+        .custom-col-2{
+            text-align: center;
+            width: 10%;
+        }
+    }
+}
+
+.errorMsg {
+    color: $red;
+}
diff --git a/dashboardv3/public/css/scss/panel.scss b/dashboardv3/public/css/scss/panel.scss
index dfa0872..931a9a6 100644
--- a/dashboardv3/public/css/scss/panel.scss
+++ b/dashboardv3/public/css/scss/panel.scss
@@ -134,4 +134,38 @@
             }
         }
     }
-}
\ No newline at end of file
+}
+
+.panel-default.custom-panel>.panel-heading {
+    color: $black;
+    cursor: pointer;
+    border-bottom: none;
+    display: inline-block;
+
+    .panel-title {
+        font-weight: normal;
+        a:hover {
+            color: $black;
+            opacity: 0.7;
+        }
+    }
+    .btn-group {
+        margin-top: 3px;
+    }
+}
+
+.panel-default.custom-panel>.panel-actions {
+    float: right;
+    margin-top: 15px;
+    button {
+        margin-right: 10px;
+        margin-top: -4px;
+    }
+}
+
+.panel-default.custom-panel>.panel-collapse>.panel-body {
+    border-top: none;
+}
+.panel-default.custom-panel>.panel-heading > .btn-group > button {
+    color: $black;
+}
diff --git a/dashboardv3/public/css/scss/table.scss b/dashboardv3/public/css/scss/table.scss
index 0f8ca75..06fb29b 100644
--- a/dashboardv3/public/css/scss/table.scss
+++ b/dashboardv3/public/css/scss/table.scss
@@ -212,6 +212,7 @@ td {
     pre.scroll-y {
         max-height: 200px;
         overflow-y: auto;
+        word-break: break-word;
     }
 
     &.searchTableName {
diff --git a/dashboardv3/public/js/templates/detail_page/DetailPageLayoutView_tmpl.html b/dashboardv3/public/js/templates/detail_page/DetailPageLayoutView_tmpl.html
index 6519863..9c7cb81 100644
--- a/dashboardv3/public/js/templates/detail_page/DetailPageLayoutView_tmpl.html
+++ b/dashboardv3/public/js/templates/detail_page/DetailPageLayoutView_tmpl.html
@@ -68,9 +68,16 @@
 <div>
     <div class="tab-content">
         <div id="tab-details" role="properties" class="tab-pane active animated fadeIn">
-            <div id="r_entityDetailTableLayoutView">
-                <div class="fontLoader-relative">
-                    <i class="fa fa-refresh fa-spin-custom"></i>
+            <div class="row">
+                <div class="col-md-6">
+                    <div id="r_entityDetailTableLayoutView">
+                        <div class="fontLoader-relative">
+                            <i class="fa fa-refresh fa-spin-custom"></i>
+                        </div>
+                    </div>
+                </div>
+                <div class="col-md-6">
+                    <div id="r_entityUserDefineView"></div>
                 </div>
             </div>
         </div>
@@ -125,4 +132,4 @@
         </div>
     </div>
 </div>
-</div>
\ No newline at end of file
+</div>
diff --git a/dashboardv3/public/js/templates/entity/EntityDetailTableLayoutView_tmpl.html b/dashboardv3/public/js/templates/entity/EntityDetailTableLayoutView_tmpl.html
index 1c01077..18a9435 100644
--- a/dashboardv3/public/js/templates/entity/EntityDetailTableLayoutView_tmpl.html
+++ b/dashboardv3/public/js/templates/entity/EntityDetailTableLayoutView_tmpl.html
@@ -14,23 +14,33 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
 -->
-<div class="entity-detail-table">
-    <div class="entity-detail-table-toggle">
-        <div class="pretty p-switch p-fill">
-            <input type="checkbox" data-id="noValueToggle" />
-            <div class="state p-primary">
-                <label>Show Empty Values</label>
+<div class="panel-group" id="accordion">
+    <div class="panel panel-default custom-panel expand_collapse_panel-icon" data-id="entity">
+        <div class="panel-heading" data-toggle="collapse" href="#collapse1" aria-expanded="true" style="width: 58%">
+            <h4 class="panel-title">
+                <a>Technical properties </a>
+            </h4>
+            <div class="btn-group pull-left">
+                <button type="button" title="Collapse"><i class="ec-icon fa"></i></button>
+            </div>
+        </div>
+        <div class="panel-actions">
+            <div class="pretty p-switch p-fill">
+                <input type="checkbox" data-id="noValueToggle" />
+                <div class="state p-primary">
+                    <label>Show Empty Values</label>
+                </div>
+            </div>
+        </div>
+        <div id="collapse1" class="panel-collapse collapse in">
+            <div class="panel-body">
+                    <div class="entity-detail-table">
+                        <table class="table">
+                            <tbody data-id="detailValue" class="hide-empty-value">
+                            </tbody>
+                        </table>
+                    </div>
             </div>
         </div>
     </div>
-    <table class="table table-quickMenu">
-        <thead>
-            <tr>
-                <th>Key</th>
-                <th>Value</th>
-            </tr>
-        </thead>
-        <tbody data-id="detailValue" class="hide-empty-value">
-        </tbody>
-    </table>
-</div>
\ No newline at end of file
+</div>
diff --git a/dashboardv3/public/js/templates/entity/EntityUserDefineItemView_tmpl.html b/dashboardv3/public/js/templates/entity/EntityUserDefineItemView_tmpl.html
new file mode 100644
index 0000000..a06039f
--- /dev/null
+++ b/dashboardv3/public/js/templates/entity/EntityUserDefineItemView_tmpl.html
@@ -0,0 +1,45 @@
+<!--
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+-->
+
+<div data-id="userDefineItems">
+    <table class="custom-table">
+        {{#each items}}
+            <tr class="custom-tr">
+                <td class="custom-col-1">
+                    <input placeholder="key" type="text"  data-type="key" data-index={{@index}} class="form-control" value={{key}}></input>
+                    <p class="errorMsg"></p>
+                </td >
+                <td  class="custom-col-0"> : </td >
+                <td  class="custom-col-1">
+                    <textarea placeholder="value"  data-type="value" data-index={{@index}} class="form-control" class="form-control">{{value}}</textarea>
+                    <p class="errorMsg"></p>
+                </td >
+                <td  class="custom-col-2">
+                    <button class="btn btn-default btn-sm" title=""  data-index={{@index}} data-id="deleteItem">
+                        <i class="fa fa-minus"> </i>
+                    </button>
+                    <button class="btn btn-default btn-sm" title="" data-index={{@index}} data-id="addItem">
+                        <i class="fa fa-plus"> </i>
+                    </button>
+                </td >
+            </tr>
+        {{/each}}
+        {{#ifCond items.length "===" 0}}
+            No properties have been created yet. To add a property, click <a href="javascript:void(0)" data-id="addItem">here</a>
+        {{/ifCond}}
+    </table>
+</div>
diff --git a/dashboardv3/public/js/templates/entity/EntityUserDefineView_tmpl.html b/dashboardv3/public/js/templates/entity/EntityUserDefineView_tmpl.html
new file mode 100644
index 0000000..5dee81d
--- /dev/null
+++ b/dashboardv3/public/js/templates/entity/EntityUserDefineView_tmpl.html
@@ -0,0 +1,80 @@
+<!--
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+-->
+<div class="panel-group" id="accordion">
+    <div class="panel panel-default custom-panel expand_collapse_panel-icon" data-id="userDefine">
+        {{#ifCond customAttibutes.length "===" 0}}
+            <div class="panel-heading collapsed" data-toggle="collapse" href="#collapse2" aria-expanded="false" style="width: 70%">
+                <h4 class="panel-title">
+                    <a>User-defined properties </a>
+                </h4>
+                <div class="btn-group pull-left">
+                    <button type="button" title="Collapse"><i class="ec-icon fa"></i></button>
+                </div>
+            </div>
+            <div class="panel-actions">
+                {{#ifCond readOnlyEntity "===" false}}
+                    <button class="btn btn-action btn-sm"  data-id="editAttr" data-original-title="Add User-Defined"> Add</button>
+                {{/ifCond}}
+            </div>
+        {{else}}
+            <div class="panel-heading" data-toggle="collapse" href="#collapse2" aria-expanded="true" style="width: 60%">
+                <h4 class="panel-title">
+                    <a>User-defined properties </a>
+                </h4>
+                <div class="btn-group pull-left">
+                    <button type="button" title="Collapse"><i class="ec-icon fa"></i></button>
+                </div>
+            </div>
+            <div class="panel-actions">
+                {{#ifCond readOnlyEntity "===" false}}
+                    <button class="btn btn-action btn-sm"  data-id="editAttr" data-original-title="Edit User-Defined Attributes">Edit</button>
+                {{/ifCond}}
+            </div>
+        {{/ifCond}}
+
+        <div id="collapse2" {{#ifCond customAttibutes.length "===" 0}} class="panel-collapse collapse" {{else}} class="panel-collapse collapse in" {{/ifCond}} >
+            <div class="panel-body">
+                    <div class="row">
+                        <div class="col-md-12">
+                            <div class="entity-detail-table">
+                                <table class="table">
+                                    {{#ifCond customAttibutes.length "===" 0}}
+                                        <span>No properties have been created yet.
+                                            {{#ifCond readOnlyEntity "==" false}}
+                                                <span>To add a property, click <a href="javascript:void(0)" data-id="editAttr">here</a></span>
+                                            {{/ifCond}}
+                                        </span>
+                                    {{/ifCond}}
+                                    <tbody>
+                                        {{#each customAttibutes}}
+                                            <tr>
+                                                <td>
+                                                    <div class="scroll-y">{{key}}</div>                                              </div></td>
+                                                <td>
+                                                    <div class="scroll-y">{{value}}</div>
+                                                </td>
+                                            </tr>
+                                        {{/each}}
+                                    </tbody>
+                                </table>
+                            </div>
+                        </div>
+                    </div>
+            </div>
+        </div>
+    </div>
+</div>
diff --git a/dashboardv3/public/js/views/detail_page/DetailPageLayoutView.js b/dashboardv3/public/js/views/detail_page/DetailPageLayoutView.js
index 682feb3..e1ab970 100644
--- a/dashboardv3/public/js/views/detail_page/DetailPageLayoutView.js
+++ b/dashboardv3/public/js/views/detail_page/DetailPageLayoutView.js
@@ -45,7 +45,8 @@ define(['require',
                 RAuditTableLayoutView: "#r_auditTableLayoutView",
                 RReplicationAuditTableLayoutView: "#r_replicationAuditTableLayoutView",
                 RProfileLayoutView: "#r_profileLayoutView",
-                RRelationshipLayoutView: "#r_relationshipLayoutView"
+                RRelationshipLayoutView: "#r_relationshipLayoutView",
+                REntityUserDefineView: "#r_entityUserDefineView",
             },
             /** ui selector cache */
             ui: {
@@ -249,6 +250,7 @@ define(['require',
                         })()
                     }
                     this.renderEntityDetailTableLayoutView(obj);
+                    this.renderEntityUserDefineView(obj);
                     this.renderRelationshipLayoutView(obj);
                     this.renderAuditTableLayoutView(obj);
                     this.renderTagTableLayoutView(obj);
@@ -496,6 +498,12 @@ define(['require',
                     that.REntityDetailTableLayoutView.show(new EntityDetailTableLayoutView(obj));
                 });
             },
+            renderEntityUserDefineView: function(obj) {
+                var that = this;
+                require(['views/entity/EntityUserDefineView'], function(EntityUserDefineView) {
+                    that.REntityUserDefineView.show(new EntityUserDefineView(obj));
+                });
+            },
             renderTagTableLayoutView: function(obj) {
                 var that = this;
                 require(['views/tag/TagDetailTableLayoutView'], function(TagDetailTableLayoutView) {
@@ -558,4 +566,4 @@ define(['require',
             }
         });
     return DetailPageLayoutView;
-});
\ No newline at end of file
+});
diff --git a/dashboardv3/public/js/views/entity/EntityDetailTableLayoutView.js b/dashboardv3/public/js/views/entity/EntityDetailTableLayoutView.js
index 381d99e..6572292 100644
--- a/dashboardv3/public/js/views/entity/EntityDetailTableLayoutView.js
+++ b/dashboardv3/public/js/views/entity/EntityDetailTableLayoutView.js
@@ -83,4 +83,4 @@ define(['require',
             }
         });
     return EntityDetailTableLayoutView;
-});
\ No newline at end of file
+});
diff --git a/dashboardv3/public/js/views/entity/EntityUserDefineItemView.js b/dashboardv3/public/js/views/entity/EntityUserDefineItemView.js
new file mode 100644
index 0000000..a649ca8
--- /dev/null
+++ b/dashboardv3/public/js/views/entity/EntityUserDefineItemView.js
@@ -0,0 +1,98 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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/entity/EntityUserDefineItemView_tmpl'
+
+], function(require, Backbone, EntityUserDefineItemView_tmpl) {
+    'use strict';
+
+    return Backbone.Marionette.ItemView.extend({
+        _viewName: 'EntityUserDefineItemView',
+
+        template: EntityUserDefineItemView_tmpl,
+
+        templateHelpers: function() {
+            return {
+                items: this.items
+            };
+        },
+
+        /** Layout sub regions */
+        regions: {},
+
+        /** ui selector cache */
+        ui: {
+            itemKey: "[data-type='key']",
+            itemValue: "[data-type='value']",
+            addItem: "[data-id='addItem']",
+            deleteItem: "[data-id='deleteItem']"
+        },
+        /** ui events hash */
+        events: function() {
+            var events = {};
+            events['input ' + this.ui.itemKey] = 'onItemKeyChange';
+            events['input ' + this.ui.itemValue] = 'onItemValueChange';
+            events['click ' + this.ui.addItem] = 'onAddItemClick';
+            events['click ' + this.ui.deleteItem] = 'onDeleteItemClick';
+            return events;
+        },
+
+        /**
+         * intialize a new GlobalExclusionComponentView Layout
+         * @constructs
+         */
+        initialize: function(options) {
+            var that = this;
+            this.editMode = options.mode;
+            if (options.items.length === 0) {
+                this.items = [{ key: "", value: "", mode: this.editMode}];
+
+            } else {
+                this.items = options.items.map(function(m) {
+                    m.mode = that.editMode;
+                    return m;
+                });
+            }
+        },
+        onRender: function() {
+
+        },
+        onAddItemClick: function(e) {
+            var el = e.currentTarget;
+            this.items.splice(parseInt(el.dataset.index) + 1, 0, { key: "", value: "", mode: this.editMode});
+            this.render();
+        },
+        onDeleteItemClick: function(e) {
+            var el = e.currentTarget;
+            this.items.splice(el.dataset.index, 1);
+            this.render();
+        },
+        onItemKeyChange: function (e) {
+            var el = e.currentTarget;
+            var val = el.value;
+            this.items[ el.dataset.index].key = val;
+        },
+        onItemValueChange: function (e) {
+            var el = e.currentTarget;
+            var val = el.value;
+            this.items[ el.dataset.index].value = el.value;
+        }
+    });
+
+});
diff --git a/dashboardv3/public/js/views/entity/EntityUserDefineView.js b/dashboardv3/public/js/views/entity/EntityUserDefineView.js
new file mode 100644
index 0000000..588703f
--- /dev/null
+++ b/dashboardv3/public/js/views/entity/EntityUserDefineView.js
@@ -0,0 +1,184 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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/entity/EntityUserDefineView_tmpl',
+'views/entity/EntityUserDefineItemView',
+'utils/CommonViewFunction',
+'modules/Modal',
+'models/VEntity',
+'utils/Utils',
+'utils/Enums'
+], function(require, Backbone, EntityUserDefineView_tmpl, EntityUserDefineItemView, CommonViewFunction, Modal, VEntity, Utils, Enums) {
+'use strict';
+
+    return Backbone.Marionette.LayoutView.extend({
+        _viewName: 'EntityUserDefineView',
+        template: EntityUserDefineView_tmpl,
+        templateHelpers: function() {
+            return {
+                customAttibutes: this.customAttibutes,
+                readOnlyEntity : this.readOnlyEntity
+            };
+        },
+        ui: {
+            addAttr: "[data-id='addAttr']",
+            editAttr: "[data-id='editAttr']",
+            deleteAttr: "[data-id='deleteAttr']"
+        },
+        events: function() {
+            var events = {};
+            events["click " + this.ui.editAttr] = 'onEditAttrClick';
+            return events;
+        },
+        initialize: function(options) {
+            _.extend(this, _.pick(options, 'entity'));
+            this.userDefineAttr = this.entity.customAttributes || [];
+            this.editMode = false;
+            this.readOnlyEntity = Enums.entityStateReadOnly[this.entity.status];
+            this.entityModel = new VEntity(this.entity);
+            this.generateTableFields();
+        },
+        onRender: function() {
+        },
+        bindEvents: {},
+        customAtributesFunc: function() {
+
+        },
+        generateTableFields: function() {
+            var that = this;
+            this.customAttibutes = [];
+            _.each(Object.keys(that.userDefineAttr), function(key, i) {
+                that.customAttibutes.push({
+                    key: key,
+                    value: that.userDefineAttr[key]
+                });
+            });
+        },
+        onEditAttrClick: function (e) {
+            this.editMode = true;
+            var options = {items: this.customAttibutes, mode: true};
+            var view = new EntityUserDefineItemView(options);
+            var modalObj = {
+                title: 'User-defined properties',
+                content: view,
+                okText: 'Save',
+                okCloses: false,
+                cancelText: "Cancel",
+                mainClass: 'modal-lg',
+                allowCancel: true,
+            };
+           this.setAttributeModal(modalObj);
+        },
+        structureAttributes: function (list) {
+            var obj={}
+            list.map(function (o) {
+                obj[o.key] = o.value;
+            });
+            return obj;
+        },
+        saveAttributes: function (list) {
+            var that = this;
+            var entityJson = that.entityModel.toJSON();
+            var properties = that.structureAttributes(list);
+            entityJson.customAttributes = properties;
+            var payload = {entity: entityJson};
+            that.entityModel.createOreditEntity({
+                data: JSON.stringify(payload),
+                type: 'POST',
+                success: function() {
+                    var msg = "User-defined properties updated successfully";
+                    that.customAttibutes = list;
+                    Utils.notifySuccess({
+                        content: msg
+                    });
+                    that.modal && that.modal.trigger('cancel');
+                    that.render();
+                },
+                error: function (e) {
+                    that.editMode = false;
+                    Utils.notifySuccess({
+                        content: e.message
+                    });
+                    that.modal && that.modal.$el.find('button.ok').attr("disabled", false);
+                },
+                complete: function () {
+                    that.modal && that.modal.$el.find('button.ok').attr("disabled", false);
+                    that.editMode = false;
+                }
+            });
+        },
+        setAttributeModal: function(modalObj) {
+            var self = this;
+            this.modal = new Modal(modalObj);
+            this.modal.open();
+            this. modal.on('ok', function() {
+                self.modal.$el.find('button.ok').attr("disabled", true);
+                var list = self.modal.$el.find("[data-type]"),
+                    keyMap = new Map(),
+                    validation = true,
+                    hasDup = [],
+                    dataList = [];
+                Array.prototype.push.apply(dataList, self.modal.options.content.items);
+                for(var i = 0; i < list.length ; i++) {
+                    var input = list[i],
+                        type = input.dataset.type,
+                        pEl = self.modal.$el.find(input.parentElement).find('p'),
+                        classes = 'form-control',
+                        val = input.value.trim();
+                        pEl[0].innerText = "";
+
+                    if (val === '') {
+                        classes = 'form-control errorClass';
+                        validation = false;
+                        pEl[0].innerText = 'Required!';
+                    } else {
+                        if (input.tagName === 'INPUT') {
+                            var duplicates = dataList.filter(function(c) {
+                                return c.key === val;
+                            });
+                            if (keyMap.has(val) || duplicates.length > 1 ) {
+                                classes = 'form-control errorClass';
+                                hasDup.push('duplicate');
+                                pEl[0].innerText = 'Duplicate key';
+                            } else {
+                                keyMap.set(val, val);
+                            }
+                        }
+                    }
+                    input.setAttribute('class', classes);
+                }
+
+                if (validation && hasDup.length === 0) {
+                    self.saveAttributes(self.modal.options.content.items);
+                } else {
+                    self.modal.$el.find('button.ok').attr("disabled", false);
+                }
+            });
+            this.modal.on('closeModal', function() {
+                self.editMode = false;
+                self.modal.trigger('cancel');
+            });
+        },
+        enableModalButton: function () {
+            var self = this;
+            self.modal.$el.find('button.ok').attr("disabled", false);
+        }
+    });
+});