Repository: incubator-atlas Updated Branches: refs/heads/master b305ba505 -> b3efebc96
ATLAS-1371: create/edit tag dialog to allow choosing of data-type for attributes Signed-off-by: Madhan Neethiraj <[email protected]> Project: http://git-wip-us.apache.org/repos/asf/incubator-atlas/repo Commit: http://git-wip-us.apache.org/repos/asf/incubator-atlas/commit/b3efebc9 Tree: http://git-wip-us.apache.org/repos/asf/incubator-atlas/tree/b3efebc9 Diff: http://git-wip-us.apache.org/repos/asf/incubator-atlas/diff/b3efebc9 Branch: refs/heads/master Commit: b3efebc9690774750d7bfa5fe43d27328746f75a Parents: b305ba5 Author: kalyanikk <[email protected]> Authored: Fri Dec 16 18:10:51 2016 +0530 Committer: Madhan Neethiraj <[email protected]> Committed: Fri Dec 16 07:10:35 2016 -0800 ---------------------------------------------------------------------- dashboardv2/public/js/models/VTag.js | 4 +- .../templates/tag/AddTagAttributeView_tmpl.html | 6 +- .../tag/TagAttributeItemView_tmpl.html | 37 ++++++++++ .../templates/tag/createTagLayoutView_tmpl.html | 18 +++-- dashboardv2/public/js/utils/UrlLinks.js | 4 +- .../public/js/views/tag/AddTagAttributeView.js | 66 +++++++++++++---- .../public/js/views/tag/CreateTagLayoutView.js | 43 ++++++++++- .../views/tag/TagAttributeDetailLayoutView.js | 76 ++++++++++++-------- .../public/js/views/tag/TagAttributeItemView.js | 70 ++++++++++++++++++ .../public/js/views/tag/TagLayoutView.js | 30 +++++++- release-log.txt | 1 + 11 files changed, 299 insertions(+), 56 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/incubator-atlas/blob/b3efebc9/dashboardv2/public/js/models/VTag.js ---------------------------------------------------------------------- diff --git a/dashboardv2/public/js/models/VTag.js b/dashboardv2/public/js/models/VTag.js index 2938572..73cf3c8 100644 --- a/dashboardv2/public/js/models/VTag.js +++ b/dashboardv2/public/js/models/VTag.js @@ -49,8 +49,8 @@ define(['require', }, options); return this.constructor.nonCrudOperation.call(this, url, 'DELETE', options); }, - saveTagAttribute: function(name, options) { - var url = UrlLinks.typesClassicationApiUrl(name); + saveTagAttribute: function(guid, options) { + var url = UrlLinks.typesClassicationApiUrl(null, guid); options = _.extend({ contentType: 'application/json', dataType: 'json' http://git-wip-us.apache.org/repos/asf/incubator-atlas/blob/b3efebc9/dashboardv2/public/js/templates/tag/AddTagAttributeView_tmpl.html ---------------------------------------------------------------------- diff --git a/dashboardv2/public/js/templates/tag/AddTagAttributeView_tmpl.html b/dashboardv2/public/js/templates/tag/AddTagAttributeView_tmpl.html index a62b079..f6e1aac 100644 --- a/dashboardv2/public/js/templates/tag/AddTagAttributeView_tmpl.html +++ b/dashboardv2/public/js/templates/tag/AddTagAttributeView_tmpl.html @@ -16,8 +16,10 @@ --> <div class="row row-margin-bottom"> <div class="col-sm-12"> - <div class="form-group"> - <input type="text" class="form-control row-margin-top" name="name" data-id="attributeId" autofocus placeholder="Attribute name" required="" value={{name}}> + <div class="clearfix"> + <button type="button" class="btn btn-success btn-sm pull-right" data-id="attributeData"><i class="fa fa-plus"></i> Add New Attribute</button> + </div> + <div class="form-group" data-id="addAttributeDiv"> </div> </div> </div> http://git-wip-us.apache.org/repos/asf/incubator-atlas/blob/b3efebc9/dashboardv2/public/js/templates/tag/TagAttributeItemView_tmpl.html ---------------------------------------------------------------------- diff --git a/dashboardv2/public/js/templates/tag/TagAttributeItemView_tmpl.html b/dashboardv2/public/js/templates/tag/TagAttributeItemView_tmpl.html new file mode 100644 index 0000000..dfd2b72 --- /dev/null +++ b/dashboardv2/public/js/templates/tag/TagAttributeItemView_tmpl.html @@ -0,0 +1,37 @@ +<!-- + * 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="row"> + <div class="col-md-7 attrTopMargin"> + <input class="form-control attributeInput" data-id="attributeInput" placeholder="Attribute name"> + </input> + </div> + <div class="col-md-3 attrTopMargin"> + <select class="form-control dataTypeSelector" data-id="dataTypeSelector"> + <option selected="selected">string</option> + <option>boolean</option> + <option>byte</option> + <option>short</option> + <option>int</option> + <option>float</option> + <option>double</option> + <option>date</option> + </select> + </div> + <div class="col-md-2 attrTopMargin attributePlusData" align="right"> + <button type="button" class="btn btn-danger btn-sm closeInput" data-id="close"><i class="fa fa-times"></i></button> + </div> +</div> http://git-wip-us.apache.org/repos/asf/incubator-atlas/blob/b3efebc9/dashboardv2/public/js/templates/tag/createTagLayoutView_tmpl.html ---------------------------------------------------------------------- diff --git a/dashboardv2/public/js/templates/tag/createTagLayoutView_tmpl.html b/dashboardv2/public/js/templates/tag/createTagLayoutView_tmpl.html index 8fa0ccc..668b09d 100644 --- a/dashboardv2/public/js/templates/tag/createTagLayoutView_tmpl.html +++ b/dashboardv2/public/js/templates/tag/createTagLayoutView_tmpl.html @@ -14,7 +14,7 @@ * See the License for the specific language governing permissions and * limitations under the License. --> -<form name="tagDefinitionform" class="css-form"> +<form name="tagDefinitionform" class="css-form" data-id="createTagForm"> <!-- <h4 style="margin-bottom:30px"></h4> --> <div class="form-group"> {{#if create}} @@ -27,9 +27,19 @@ <input class="form-control row-margin-bottom" data-id="description" value="{{description}}" placeholder="Description"> </input> {{#if create}} - <span class="row-margin-bottom">Select tags to inherit attributes(optional)</span> - <p class="attributeText">Attributes define additional properties for the tag</p> - <select class="form-control" data-id="parentTagList" multiple="multiple"></select> + <div class="row row-margin-bottom"> + <div class="col-md-12"> + <span>Select tags to inherit attributes(optional)</span> + <p class="attributeText">Attributes define additional properties for the tag</p> + <select class="form-control" data-id="parentTagList" multiple="multiple"></select> + </div> + </div> + <div class="clearfix"> + <span class="pull-left">Attributes(optional)</span> + <button type="button" class="btn btn-success btn-sm pull-right" data-id="attributeData"><i class="fa fa-plus"></i> Add New Attribute</button> + </div> {{/if}} + <div data-id="addAttributeDiv"> + </div> </div> </form> http://git-wip-us.apache.org/repos/asf/incubator-atlas/blob/b3efebc9/dashboardv2/public/js/utils/UrlLinks.js ---------------------------------------------------------------------- diff --git a/dashboardv2/public/js/utils/UrlLinks.js b/dashboardv2/public/js/utils/UrlLinks.js index 4071b07..901de5a 100644 --- a/dashboardv2/public/js/utils/UrlLinks.js +++ b/dashboardv2/public/js/utils/UrlLinks.js @@ -52,10 +52,12 @@ define(['require', 'utils/Enums'], function(require, Enums) { entityCollectionaudit: function(guid) { return this.baseUrl + '/entities/' + guid + '/audit'; }, - typesClassicationApiUrl: function(name) { + typesClassicationApiUrl: function(name, guid) { var typeUrl = this.baseUrlV2 + '/types/classificationdef' if (name) { return typeUrl + '/name/' + name; + } else if (guid) { + return typeUrl + '/guid/' + guid; } else { return typeUrl; } http://git-wip-us.apache.org/repos/asf/incubator-atlas/blob/b3efebc9/dashboardv2/public/js/views/tag/AddTagAttributeView.js ---------------------------------------------------------------------- diff --git a/dashboardv2/public/js/views/tag/AddTagAttributeView.js b/dashboardv2/public/js/views/tag/AddTagAttributeView.js index 6d38162..3108279 100644 --- a/dashboardv2/public/js/views/tag/AddTagAttributeView.js +++ b/dashboardv2/public/js/views/tag/AddTagAttributeView.js @@ -1,4 +1,3 @@ - /** * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file @@ -20,36 +19,77 @@ define(['require', 'backbone', 'hbs!tmpl/tag/AddTagAttributeView_tmpl', + 'views/tag/TagAttributeItemView', -], function(require, Backbone, AddTagAttributeView_tmpl) { +], function(require, Backbone, AddTagAttributeView_tmpl, TagAttributeItemView) { 'use strict'; - return Backbone.Marionette.LayoutView.extend( + return Backbone.Marionette.CompositeView.extend( /** @lends GlobalExclusionListView */ { template: AddTagAttributeView_tmpl, + templateHelpers: function() { + return { + create: this.create, + description: this.description + }; + }, + + childView: TagAttributeItemView, - /** Layout sub regions */ - regions: {}, + childViewContainer: "[data-id='addAttributeDiv']", + childViewOptions: function() { + return { + // saveButton: this.ui.saveButton, + parentView: this + }; + }, /** ui selector cache */ ui: { close: "[data-id='close']", - attributeId: "[data-id='attributeId']" + attributeId: "[data-id='attributeId']", + attributeData: "[data-id='attributeData']", + addAttributeDiv: "[data-id='addAttributeDiv']" }, events: function() { var events = {}; + events["click " + this.ui.attributeData] = "onClickAddAttriBtn"; return events; }, - /** - * intialize a new GlobalExclusionComponentView Layout - * @constructs - */ initialize: function(options) { - this.parentView = options.parentView; + // this.parentView = options.parentView; + this.collection = new Backbone.Collection(); + this.collectionAttribute(); + }, + onRender: function() { + this.ui.addAttributeDiv.find('.closeInput').hide(); + if (!('placeholder' in HTMLInputElement.prototype)) { + this.ui.addAttributeDiv.find('input,textarea').placeholder(); + } + }, + bindEvents: function() {}, + collectionAttribute: function() { + this.collection.add(new Backbone.Model({ + "name": "", + "typeName": "string", + "isOptional": true, + "cardinality": "SINGLE", + "valuesMinCount": 0, + "valuesMaxCount": 1, + "isUnique": false, + "isIndexable": false + })); }, - onRender: function() {}, - bindEvents: function() {} + onClickAddAttriBtn: function() { + if (this.ui.addAttributeDiv.find("input").length > 0) { + this.ui.addAttributeDiv.find('.closeInput').show(); + }; + this.collectionAttribute(); + if (!('placeholder' in HTMLInputElement.prototype)) { + this.ui.addAttributeDiv.find('input,textarea').placeholder(); + } + } }); }); http://git-wip-us.apache.org/repos/asf/incubator-atlas/blob/b3efebc9/dashboardv2/public/js/views/tag/CreateTagLayoutView.js ---------------------------------------------------------------------- diff --git a/dashboardv2/public/js/views/tag/CreateTagLayoutView.js b/dashboardv2/public/js/views/tag/CreateTagLayoutView.js index fee04b5..bf8f88d 100644 --- a/dashboardv2/public/js/views/tag/CreateTagLayoutView.js +++ b/dashboardv2/public/js/views/tag/CreateTagLayoutView.js @@ -20,10 +20,11 @@ define(['require', 'backbone', 'hbs!tmpl/tag/createTagLayoutView_tmpl', 'utils/Utils', + 'views/tag/TagAttributeItemView', 'platform' -], function(require, Backbone, CreateTagLayoutViewTmpl, Utils, platform) { +], function(require, Backbone, CreateTagLayoutViewTmpl, Utils, TagAttributeItemView, platform) { - var CreateTagLayoutView = Backbone.Marionette.LayoutView.extend( + var CreateTagLayoutView = Backbone.Marionette.CompositeView.extend( /** @lends CreateTagLayoutView */ { _viewName: 'CreateTagLayoutView', @@ -40,16 +41,30 @@ define(['require', /** Layout sub regions */ regions: {}, + childView: TagAttributeItemView, + + childViewContainer: "[data-id='addAttributeDiv']", + + childViewOptions: function() { + return { + // saveButton: this.ui.saveButton, + parentView: this + }; + }, /** ui selector cache */ ui: { tagName: "[data-id='tagName']", parentTag: "[data-id='parentTagList']", description: "[data-id='description']", - title: "[data-id='title']" + title: "[data-id='title']", + attributeData: "[data-id='attributeData']", + addAttributeDiv: "[data-id='addAttributeDiv']", + createTagForm: '[data-id="createTagForm"]' }, /** ui events hash */ events: function() { var events = {}; + events["click " + this.ui.attributeData] = "onClickAddAttriBtn"; return events; }, /** @@ -65,6 +80,7 @@ define(['require', } else { this.create = true; } + this.collection = new Backbone.Collection(); }, bindEvents: function() {}, onRender: function() { @@ -73,6 +89,9 @@ define(['require', } else { this.ui.title.html('<span>' + this.tag + '</span>'); } + if (!('placeholder' in HTMLInputElement.prototype)) { + this.ui.createTagForm.find('input,textarea').placeholder(); + } }, tagCollectionList: function() { var str = '', @@ -91,6 +110,24 @@ define(['require', allowClear: true }); } + }, + collectionAttribute: function() { + this.collection.add(new Backbone.Model({ + "name": "", + "typeName": "string", + "isOptional": true, + "cardinality": "SINGLE", + "valuesMinCount": 0, + "valuesMaxCount": 1, + "isUnique": false, + "isIndexable": false + })); + }, + onClickAddAttriBtn: function() { + this.collectionAttribute(); + if (!('placeholder' in HTMLInputElement.prototype)) { + this.ui.addAttributeDiv.find('input,textarea').placeholder(); + } } }); return CreateTagLayoutView; http://git-wip-us.apache.org/repos/asf/incubator-atlas/blob/b3efebc9/dashboardv2/public/js/views/tag/TagAttributeDetailLayoutView.js ---------------------------------------------------------------------- diff --git a/dashboardv2/public/js/views/tag/TagAttributeDetailLayoutView.js b/dashboardv2/public/js/views/tag/TagAttributeDetailLayoutView.js index 4dc8c38..6c3cfe4 100644 --- a/dashboardv2/public/js/views/tag/TagAttributeDetailLayoutView.js +++ b/dashboardv2/public/js/views/tag/TagAttributeDetailLayoutView.js @@ -48,7 +48,7 @@ define(['require', addTagPlus: '[data-id="addTagPlus"]', description: '[data-id="description"]', descriptionTextArea: '[data-id="descriptionTextArea"]', - publishButton: '[data-id="publishButton"]', + publishButton: '[data-id="publishButton"]' }, /** ui events hash */ events: function() { @@ -68,7 +68,7 @@ define(['require', }, bindEvents: function() { this.listenTo(this.collection, 'reset', function() { - this.model = this.collection.findWhere({ name: this.tag }); + this.model = this.collection.fullCollection.findWhere({ name: this.tag }); this.renderTagDetail(); }, this); this.listenTo(this.tagCollection, 'error', function(error, response) { @@ -82,7 +82,7 @@ define(['require', }, onRender: function() { if (this.collection.models.length && !this.model) { - this.model = this.collection.findWhere({ name: this.tag }); + this.model = this.collection.fullCollection.findWhere({ name: this.tag }); this.renderTagDetail(); } this.bindEvents(); @@ -111,7 +111,25 @@ define(['require', }, onSaveButton: function(saveObject, message) { var that = this; - this.model.saveTagAttribute(this.model.get('name'), { + var validate = true; + if (this.modal.$el.find(".attributeInput").length > 1) { + this.modal.$el.find(".attributeInput").each(function() { + if ($(this).val() === "") { + $(this).css('borderColor', "red") + validate = false; + } + }); + } + this.modal.$el.find(".attributeInput").keyup(function() { + $(this).css('borderColor', "#e8e9ee"); + }); + if (!validate) { + Utils.notifyInfo({ + content: "Please fill the attributes or delete the input box" + }); + return; + } + this.model.saveTagAttribute(this.model.get('guid'), { data: JSON.stringify(saveObject), success: function(model, response) { that.model.set(model); @@ -119,6 +137,7 @@ define(['require', Utils.notifySuccess({ content: message }); + that.modal.close(); }, error: function(model, response) { if (response.responseJSON && response.responseJSON.error) { @@ -135,33 +154,34 @@ define(['require', 'modules/Modal' ], function(AddTagAttributeView, Modal) { - var view = new AddTagAttributeView(), - modal = new Modal({ - title: 'Add Attribute', - content: view, - cancelText: "Cancel", - okText: 'Add', - allowCancel: true, - }).open(); - modal.on('ok', function() { - var attributeName = $(view.el).find("input").val(); - var attributes = _.clone(that.model.get('attributeDefs')); - if (!_.isArray(attributes)) { - attributes = [attributes]; + var view = new AddTagAttributeView(); + that.modal = new Modal({ + title: 'Add Attribute', + content: view, + cancelText: "Cancel", + okText: 'Add', + okCloses: false, + allowCancel: true, + }).open(); + that.modal.$el.find('button.ok').attr("disabled", "true"); + $(view.ui.addAttributeDiv).on('keyup', that.modal.$el.find('attributeInput'), function(e) { + if ((e.keyCode == 8 || e.keyCode == 46 || e.keyCode == 32) && e.target.value.trim() == "") { + that.modal.$el.find('button.ok').attr("disabled", "disabled"); + } else { + that.modal.$el.find('button.ok').removeAttr("disabled"); } - attributes.push({ - "name": attributeName, - "typeName": "string", - "cardinality": "SINGLE", - "isUnique": false, - "indexable": true, - "isOptional":true + }); + that.modal.on('ok', function() { + var newAttributeList = view.collection.toJSON(); + var saveJSON = JSON.parse(JSON.stringify(that.model.toJSON())); + var oldAttributeList = saveJSON.attributeDefs; + _.each(newAttributeList, function(obj) { + oldAttributeList.push(obj); }); - var saveData = _.extend(that.model.toJSON(), { 'attributeDefs': attributes }); - that.onSaveButton(saveData, Messages.addAttributeSuccessMessage); + that.onSaveButton(saveJSON, Messages.addAttributeSuccessMessage); }); - modal.on('closeModal', function() { - modal.trigger('cancel'); + that.modal.on('closeModal', function() { + that.modal.trigger('cancel'); }); }); }, http://git-wip-us.apache.org/repos/asf/incubator-atlas/blob/b3efebc9/dashboardv2/public/js/views/tag/TagAttributeItemView.js ---------------------------------------------------------------------- diff --git a/dashboardv2/public/js/views/tag/TagAttributeItemView.js b/dashboardv2/public/js/views/tag/TagAttributeItemView.js new file mode 100644 index 0000000..2482543 --- /dev/null +++ b/dashboardv2/public/js/views/tag/TagAttributeItemView.js @@ -0,0 +1,70 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +define(['require', + 'backbone', + 'hbs!tmpl/tag/TagAttributeItemView_tmpl' + +], function(require, Backbone, TagAttributeItemViewTmpl) { + 'use strict'; + + return Backbone.Marionette.ItemView.extend( + /** @lends GlobalExclusionListView */ + { + + template: TagAttributeItemViewTmpl, + + /** Layout sub regions */ + regions: {}, + + /** ui selector cache */ + ui: { + attributeInput: "[data-id='attributeInput']", + close: "[data-id='close']", + dataTypeSelector: "[data-id='dataTypeSelector']", + }, + /** ui events hash */ + events: function() { + var events = {}; + events["keyup " + this.ui.attributeInput] = function(e) { + this.model.set({ "name": e.target.value.trim() }); + }; + events["change " + this.ui.dataTypeSelector] = function(e) { + this.model.set({ "typeName": e.target.value.trim() }); + }; + events["click " + this.ui.close] = 'onCloseButton'; + return events; + }, + + /** + * intialize a new GlobalExclusionComponentView Layout + * @constructs + */ + initialize: function(options) { + this.parentView = options.parentView; + }, + onRender: function() { + + }, + bindEvents: function() {}, + onCloseButton: function() { + if (this.parentView.collection.models.length > 0) { + this.model.destroy(); + } + } + }); +}); http://git-wip-us.apache.org/repos/asf/incubator-atlas/blob/b3efebc9/dashboardv2/public/js/views/tag/TagLayoutView.js ---------------------------------------------------------------------- diff --git a/dashboardv2/public/js/views/tag/TagLayoutView.js b/dashboardv2/public/js/views/tag/TagLayoutView.js index 1994951..6997658 100644 --- a/dashboardv2/public/js/views/tag/TagLayoutView.js +++ b/dashboardv2/public/js/views/tag/TagLayoutView.js @@ -178,6 +178,7 @@ define(['require', title: 'Create a new tag', content: view, cancelText: "Cancel", + okCloses: false, okText: 'Create', allowCancel: true, }).open(); @@ -198,27 +199,50 @@ define(['require', }); }); modal.on('ok', function() { - that.onCreateButton(view); + that.onCreateButton(view, modal); }); modal.on('closeModal', function() { modal.trigger('cancel'); }); }); }, - onCreateButton: function(ref) { + onCreateButton: function(ref, modal) { var that = this; + var validate = true; + if (modal.$el.find(".attributeInput").length > 0) { + modal.$el.find(".attributeInput").each(function() { + if ($(this).val() === "") { + $(this).css('borderColor', "red") + validate = false; + } + }); + } + modal.$el.find(".attributeInput").keyup(function() { + $(this).css('borderColor', "#e8e9ee"); + }); + if (!validate) { + Utils.notifyInfo({ + content: "Please fill the attributes or delete the input box" + }); + return; + } this.name = ref.ui.tagName.val(); this.description = ref.ui.description.val(); var superTypes = []; if (ref.ui.parentTag.val() && ref.ui.parentTag.val()) { superTypes = ref.ui.parentTag.val(); } + var attributeObj = ref.collection.toJSON(); + if (ref.collection.length === 1 && ref.collection.first().get("name") === "") { + attributeObj = []; + } this.json = { 'name': this.name, 'description': this.description, "typeVersion": "2", "version": "2", 'superTypes': superTypes.length ? superTypes : [], + "attributeDefs": attributeObj }; new this.collection.model().set(this.json).save(null, { success: function(model, response) { @@ -229,7 +253,7 @@ define(['require', Utils.notifySuccess({ content: "Tag " + that.name + Messages.addSuccessMessage }); - + modal.trigger('cancel'); }, error: function(model, response) { if (response.responseJSON && response.responseJSON.error) { http://git-wip-us.apache.org/repos/asf/incubator-atlas/blob/b3efebc9/release-log.txt ---------------------------------------------------------------------- diff --git a/release-log.txt b/release-log.txt index f63842f..15e042d 100644 --- a/release-log.txt +++ b/release-log.txt @@ -9,6 +9,7 @@ ATLAS-1060 Add composite indexes for exact match performance improvements for al ATLAS-1127 Modify creation and modification timestamps to Date instead of Long(sumasai) ALL CHANGES: +ATLAS-1371 create/edit tag dialog to allow choosing of data-type for attributes (Kalyanikashikar via mneethiraj) ATLAS-1395 Lineage improvement for tooltip (kevalbhatt via mneethiraj) ATLAS-1193 UI to create/update entities (Kalyanikashikar via mneethiraj) ATLAS-1304 Redundant code removal and code simplification (apoorvnaik via mneethiraj)
