Repository: incubator-atlas Updated Branches: refs/heads/master c8f9f363b -> a7870cded
ATLAS-1502: added configuration to restrict entity-types editable via UI 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/a7870cde Tree: http://git-wip-us.apache.org/repos/asf/incubator-atlas/tree/a7870cde Diff: http://git-wip-us.apache.org/repos/asf/incubator-atlas/diff/a7870cde Branch: refs/heads/master Commit: a7870cdede63eca6a11e1fd5d42824d0efd63186 Parents: c8f9f36 Author: kalyanikk <[email protected]> Authored: Tue Jan 31 14:49:13 2017 +0530 Committer: Madhan Neethiraj <[email protected]> Committed: Tue Jan 31 12:26:44 2017 -0800 ---------------------------------------------------------------------- dashboardv2/public/css/scss/tag.scss | 4 + dashboardv2/public/js/main.js | 10 ++ dashboardv2/public/js/router/Router.js | 20 ++- .../detail_page/DetailPageLayoutView_tmpl.html | 2 +- .../templates/search/SearchLayoutView_tmpl.html | 5 - .../search/SearchResultLayoutView_tmpl.html | 8 + dashboardv2/public/js/utils/Overrides.js | 9 + .../js/views/audit/AuditTableLayoutView.js | 2 +- .../views/audit/CreateAuditTableLayoutView.js | 24 ++- .../views/detail_page/DetailPageLayoutView.js | 15 +- .../js/views/entity/CreateEntityLayoutView.js | 173 +++++++++++-------- .../js/views/search/SearchDetailLayoutView.js | 5 +- .../public/js/views/search/SearchLayoutView.js | 29 +--- .../js/views/search/SearchResultLayoutView.js | 88 +++++++--- .../public/js/views/tag/addTagModalView.js | 4 +- .../atlas/web/resources/AdminResource.java | 30 ++++ 16 files changed, 276 insertions(+), 152 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/incubator-atlas/blob/a7870cde/dashboardv2/public/css/scss/tag.scss ---------------------------------------------------------------------- diff --git a/dashboardv2/public/css/scss/tag.scss b/dashboardv2/public/css/scss/tag.scss index 1f9561d..9cc6a3c 100644 --- a/dashboardv2/public/css/scss/tag.scss +++ b/dashboardv2/public/css/scss/tag.scss @@ -407,3 +407,7 @@ legend.scheduler-border { .topMargin { margin-top: 13px; } + +.entityLink { + font-size: 16px; +} http://git-wip-us.apache.org/repos/asf/incubator-atlas/blob/a7870cde/dashboardv2/public/js/main.js ---------------------------------------------------------------------- diff --git a/dashboardv2/public/js/main.js b/dashboardv2/public/js/main.js index 2ddf1aa..2ba87a7 100644 --- a/dashboardv2/public/js/main.js +++ b/dashboardv2/public/js/main.js @@ -182,6 +182,16 @@ require(['App', if (response && response['atlas.entity.update.allowed'] !== undefined) { Globals.entityUpdate = response['atlas.entity.update.allowed']; } + if (response && response['atlas.ui.editable.entity.types'] !== undefined) { + var entityTypeList = response['atlas.ui.editable.entity.types'].trim().split(","); + if (entityTypeList.length) { + if (entityTypeList[0] === "*") { + Globals.entityTypeConfList = []; + } else if (entityTypeList.length > 0) { + Globals.entityTypeConfList = entityTypeList; + } + } + } App.start(); } }); http://git-wip-us.apache.org/repos/asf/incubator-atlas/blob/a7870cde/dashboardv2/public/js/router/Router.js ---------------------------------------------------------------------- diff --git a/dashboardv2/public/js/router/Router.js b/dashboardv2/public/js/router/Router.js index fa4a08a..7394946 100644 --- a/dashboardv2/public/js/router/Router.js +++ b/dashboardv2/public/js/router/Router.js @@ -171,7 +171,6 @@ define([ 'collection': that.tagCollection })); } else { - App.rSideNav.currentView.RTagLayoutView.currentView.manualRender(tagName); App.rSideNav.currentView.selectTab(); } @@ -191,7 +190,9 @@ define([ 'views/site/Header', 'views/business_catalog/BusinessCatalogLayoutView', 'views/business_catalog/SideNavLayoutView', - ], function(Header, BusinessCatalogLayoutView, SideNavLayoutView) { + 'views/search/SearchDetailLayoutView', + ], function(Header, BusinessCatalogLayoutView, SideNavLayoutView, SearchDetailLayoutView) { + var paramObj = Utils.getUrlState.getQueryParams(); App.rNHeader.show(new Header({ 'globalVent': that.globalVent })); if (!App.rSideNav.currentView) { App.rSideNav.show(new SideNavLayoutView({ @@ -206,8 +207,16 @@ define([ App.rSideNav.currentView.RBusinessCatalogLayoutView.currentView.manualRender(undefined, true); } } - App.rNContent.$el.html(''); - App.rNContent.destroy(); + if (Globals.entityCreate && Utils.getUrlState.isSearchTab()) { + App.rNContent.show(new SearchDetailLayoutView({ + 'globalVent': that.globalVent, + 'value': paramObj, + 'initialView': true + })) + } else { + App.rNContent.$el.html(""); + App.rNContent.destroy(); + } }); }, searchResult: function() { @@ -232,7 +241,8 @@ define([ App.rSideNav.currentView.selectTab(); App.rNContent.show(new SearchDetailLayoutView({ 'globalVent': that.globalVent, - 'value': paramObj + 'value': paramObj, + 'initialView': paramObj.query.trim().length === 0 })); }); }, http://git-wip-us.apache.org/repos/asf/incubator-atlas/blob/a7870cde/dashboardv2/public/js/templates/detail_page/DetailPageLayoutView_tmpl.html ---------------------------------------------------------------------- diff --git a/dashboardv2/public/js/templates/detail_page/DetailPageLayoutView_tmpl.html b/dashboardv2/public/js/templates/detail_page/DetailPageLayoutView_tmpl.html index 1de3608..95cf62a 100644 --- a/dashboardv2/public/js/templates/detail_page/DetailPageLayoutView_tmpl.html +++ b/dashboardv2/public/js/templates/detail_page/DetailPageLayoutView_tmpl.html @@ -23,7 +23,7 @@ <a href="javascript:void(0);" class="backButton" data-id="backButton"><i class="fa fa-chevron-left"></i> Back To Results</a> </div> <h1><span data-id="title"></span></h1> {{#if entityUpdate}} - <button data-id="editButton" class="btn btn-default pull-right editbutton" id="editText"><i class="fa fa-pencil"></i></button> + <button data-id="editButton" style="display:none" class="btn btn-default pull-right editbutton" id="editText"><i class="fa fa-pencil"></i></button> {{/if}} <div class="tagTerm"> <span class="tagSpan">Tags:</span> http://git-wip-us.apache.org/repos/asf/incubator-atlas/blob/a7870cde/dashboardv2/public/js/templates/search/SearchLayoutView_tmpl.html ---------------------------------------------------------------------- diff --git a/dashboardv2/public/js/templates/search/SearchLayoutView_tmpl.html b/dashboardv2/public/js/templates/search/SearchLayoutView_tmpl.html index 7301ebc..5ccfe18 100644 --- a/dashboardv2/public/js/templates/search/SearchLayoutView_tmpl.html +++ b/dashboardv2/public/js/templates/search/SearchLayoutView_tmpl.html @@ -15,11 +15,6 @@ * limitations under the License. --> <div class="row row-margin-bottom"> - {{#if entityCreate}} - <div class="col-sm-12"> - <button class="btn btn-atlasAction btn-atlas pull-left" data-id="createEntity"><i class="fa fa-plus"></i> Create Entity</button> - </div> - {{/if}} <div class="col-sm-12" style="margin:15px 0px;"> <div class="row"> <div class="col-md-6"> http://git-wip-us.apache.org/repos/asf/incubator-atlas/blob/a7870cde/dashboardv2/public/js/templates/search/SearchResultLayoutView_tmpl.html ---------------------------------------------------------------------- diff --git a/dashboardv2/public/js/templates/search/SearchResultLayoutView_tmpl.html b/dashboardv2/public/js/templates/search/SearchResultLayoutView_tmpl.html index 32a0083..eece7d2 100644 --- a/dashboardv2/public/js/templates/search/SearchResultLayoutView_tmpl.html +++ b/dashboardv2/public/js/templates/search/SearchResultLayoutView_tmpl.html @@ -32,6 +32,14 @@ </ul> </div> <div id="r_searchResultTableLayoutView"> + {{#if entityCreate}} + <div class="entityLink" style="display:none"> + <h1><b>Atlas Search</b></h1> + <p class="entityLink">Search Atlas for existing entities or + <a href="javascript:void(0)" data-id='createEntity'> create new entity </a><i class="fa fa-question-circle" aria-hidden="true"></i> + </p> + </div> + {{/if}} </div> </div> </div> http://git-wip-us.apache.org/repos/asf/incubator-atlas/blob/a7870cde/dashboardv2/public/js/utils/Overrides.js ---------------------------------------------------------------------- diff --git a/dashboardv2/public/js/utils/Overrides.js b/dashboardv2/public/js/utils/Overrides.js index d6d9b6c..b6fc17c 100644 --- a/dashboardv2/public/js/utils/Overrides.js +++ b/dashboardv2/public/js/utils/Overrides.js @@ -40,6 +40,15 @@ define(['require', 'utils/Utils', 'marionette', 'backgrid', 'asBreadcrumbs', 'jq }) ]); } + _.mixin({ + isEmptyArray: function(val) { + if (val && _.isArray(val)) { + return _.isEmpty(val); + } else { + return false; + } + } + }); // For placeholder support if (!('placeholder' in HTMLInputElement.prototype)) { http://git-wip-us.apache.org/repos/asf/incubator-atlas/blob/a7870cde/dashboardv2/public/js/views/audit/AuditTableLayoutView.js ---------------------------------------------------------------------- diff --git a/dashboardv2/public/js/views/audit/AuditTableLayoutView.js b/dashboardv2/public/js/views/audit/AuditTableLayoutView.js index dd4adda..2c0bc8c 100644 --- a/dashboardv2/public/js/views/audit/AuditTableLayoutView.js +++ b/dashboardv2/public/js/views/audit/AuditTableLayoutView.js @@ -147,7 +147,7 @@ define(['require', that.$('.fontLoader').hide(); that.$('.auditTable').show(); that.renderOffset(options); - if ((that.entityCollection.models.length < that.count && that.currPage == 1) && that.next == that.entityCollection.last().get('eventKey')) { + if (that.entityCollection && (that.entityCollection.models.length < that.count && that.currPage == 1) && that.next == that.entityCollection.last().get('eventKey')) { options.next.attr('disabled', true); options.previous.removeAttr("disabled"); } else { http://git-wip-us.apache.org/repos/asf/incubator-atlas/blob/a7870cde/dashboardv2/public/js/views/audit/CreateAuditTableLayoutView.js ---------------------------------------------------------------------- diff --git a/dashboardv2/public/js/views/audit/CreateAuditTableLayoutView.js b/dashboardv2/public/js/views/audit/CreateAuditTableLayoutView.js index 2b43b59..330809f 100644 --- a/dashboardv2/public/js/views/audit/CreateAuditTableLayoutView.js +++ b/dashboardv2/public/js/views/audit/CreateAuditTableLayoutView.js @@ -20,8 +20,9 @@ define(['require', 'backbone', 'hbs!tmpl/audit/CreateAuditTableLayoutView_tmpl', 'utils/Enums', - 'utils/CommonViewFunction' -], function(require, Backbone, CreateAuditTableLayoutViewTmpl, Enums, CommonViewFunction) { + 'utils/CommonViewFunction', + 'utils/Utils' +], function(require, Backbone, CreateAuditTableLayoutViewTmpl, Enums, CommonViewFunction, Utils) { 'use strict'; var CreateAuditTableLayoutView = Backbone.Marionette.LayoutView.extend( @@ -65,11 +66,17 @@ define(['require', if (this.entityModel.get('details').search('{') >= 0) { var appendedString = "{" + this.entityModel.get('details') + "}"; var auditData = appendedString.split('"')[0].split(':')[0].split("{")[1]; - var detailsObject = JSON.parse(appendedString.replace("{" + auditData + ":", '{"' + auditData + '":'))[auditData]; + try { + var detailsObject = JSON.parse(appendedString.replace("{" + auditData + ":", '{"' + auditData + '":'))[auditData]; + } catch (err) { + Utils.serverErrorHandler(); + } //Append string for JSON parse - var valueObject = detailsObject.values; - if (this.action == Enums.auditAction.TAG_ADD) { - this.ui.auditHeaderValue.html('<th>' + Enums.auditAction.TAG_ADD + '</th>'); + if (detailsObject) { + var valueObject = detailsObject.values; + } + if ((this.action == Enums.auditAction.TAG_ADD || Enums.auditAction.ENTITY_CREATE) && detailsObject) { + this.ui.auditHeaderValue.html('<th>' + (this.action === Enums.auditAction.ENTITY_CREATE ? Enums.auditAction.ENTITY_CREATE : Enums.auditAction.TAG_ADD) + '</th>'); this.ui.auditValue.html("<tr><td>" + _.escape(detailsObject.typeName) + "</td></tr>"); } else { this.ui.auditHeaderValue.html('<th>Key</th><th>New Value</th>'); @@ -84,9 +91,8 @@ define(['require', } } } else if (this.action == Enums.auditAction.TAG_DELETE || Enums.auditAction.ENTITY_DELETE) { - //var appendedString = this.entityModel.get('details').split(':'); - this.ui.auditHeaderValue.html('<th>' + this.action + '</th>'); - this.ui.auditValue.html("<tr><td>" + this.entityObject.name + "</td></tr>"); + this.ui.auditHeaderValue.html('<th>' + Enums.auditAction.TAG_DELETE || Enums.auditAction.ENTITY_DELETE + '</th>'); + this.ui.auditValue.html("<tr><td>" + (this.entityObject.name || this.entityObject.qualifiedName) + "</td></tr>"); } }, http://git-wip-us.apache.org/repos/asf/incubator-atlas/blob/a7870cde/dashboardv2/public/js/views/detail_page/DetailPageLayoutView.js ---------------------------------------------------------------------- diff --git a/dashboardv2/public/js/views/detail_page/DetailPageLayoutView.js b/dashboardv2/public/js/views/detail_page/DetailPageLayoutView.js index c959229..d778e3e 100644 --- a/dashboardv2/public/js/views/detail_page/DetailPageLayoutView.js +++ b/dashboardv2/public/js/views/detail_page/DetailPageLayoutView.js @@ -164,13 +164,21 @@ define(['require', } else { this.addTagToTerms([]); } + if (Globals.entityTypeConfList && _.isEmptyArray(Globals.entityTypeConfList)) { + this.ui.editButton.show(); + } else { + if (_.contains(Globals.entityTypeConfList, collectionJSON.typeName)) { + this.ui.editButton.show(); + } + } } this.hideLoader(); - this.auditVent.trigger("reset:collection"); this.renderEntityDetailTableLayoutView(); + this.renderAuditTableLayoutView(this.id, collectionJSON.attributes); this.renderTagTableLayoutView(tagGuid); this.renderTermTableLayoutView(tagGuid); - this.renderAuditTableLayoutView(this.id, collectionJSON.attributes); + this.renderLineageLayoutView(this.id); + this.renderSchemaLayoutView(this.id); }, this); this.listenTo(this.collection, 'error', function(model, response) { this.$('.fontLoader').hide(); @@ -185,9 +193,6 @@ define(['require', var that = this; Utils.showTitleLoader(this.$('.page-title .fontLoader'), this.$('.entityDetail')); this.$('.fontLoader').show(); // to show tab loader - this.renderLineageLayoutView(this.id); - this.renderSchemaLayoutView(this.id); - }, fetchCollection: function() { this.collection.fetch({ reset: true }); http://git-wip-us.apache.org/repos/asf/incubator-atlas/blob/a7870cde/dashboardv2/public/js/views/entity/CreateEntityLayoutView.js ---------------------------------------------------------------------- diff --git a/dashboardv2/public/js/views/entity/CreateEntityLayoutView.js b/dashboardv2/public/js/views/entity/CreateEntityLayoutView.js index 9f4e1d7..1491b2e 100644 --- a/dashboardv2/public/js/views/entity/CreateEntityLayoutView.js +++ b/dashboardv2/public/js/views/entity/CreateEntityLayoutView.js @@ -21,7 +21,6 @@ define(['require', 'hbs!tmpl/entity/CreateEntityLayoutView_tmpl', 'utils/Utils', 'collection/VTagList', - 'collection/VCommonList', 'collection/VEntityList', 'models/VEntity', 'modules/Modal', @@ -30,8 +29,9 @@ define(['require', 'moment', 'utils/UrlLinks', 'collection/VSearchList', - 'utils/Enums' -], function(require, Backbone, CreateEntityLayoutViewTmpl, Utils, VTagList, VCommonList, VEntityList, VEntity, Modal, Messages, datepicker, moment, UrlLinks, VSearchList, Enums) { + 'utils/Enums', + 'utils/Globals' +], function(require, Backbone, CreateEntityLayoutViewTmpl, Utils, VTagList, VEntityList, VEntity, Modal, Messages, datepicker, moment, UrlLinks, VSearchList, Enums, Globals) { var CreateEntityLayoutView = Backbone.Marionette.LayoutView.extend( /** @lends CreateEntityLayoutView */ @@ -53,9 +53,7 @@ define(['require', ui: { entityName: "[data-id='entityName']", entityList: "[data-id='entityList']", - description: "[data-id='description']", entityInputData: "[data-id='entityInputData']", - entityLegend: "[data-id='entityLegend']", toggleRequired: 'input[name="toggleRequired"]', assetName: "[data-id='assetName']", entityInput: "[data-id='entityInput']" @@ -77,7 +75,6 @@ define(['require', _.extend(this, _.pick(options, 'guid', 'callback', 'showLoader')); var that = this, entityTitle, okLabel; - this.entityDetailCollection = new VCommonList(); this.searchCollection = new VSearchList(); this.searchCollection.url = UrlLinks.searchApiUrl(Enums.searchUrlType.DSL); this.selectStoreCollection = new Backbone.Collection(); @@ -187,7 +184,15 @@ define(['require', return model.get('name'); } this.collection.fullCollection.sort().each(function(val) { - str += '<option>' + _.escape(val.get("name")) + '</option>'; + if (Globals.entityTypeConfList) { + if (_.isEmptyArray(Globals.entityTypeConfList)) { + str += '<option>' + _.escape(val.get("name")) + '</option>'; + } else { + if (_.contains(Globals.entityTypeConfList, val.get("name"))) { + str += '<option>' + _.escape(val.get("name")) + '</option>'; + } + } + } }); this.ui.entityList.html(str); } @@ -207,6 +212,23 @@ define(['require', } }, + longValidation: function(that) { + that.$('input[data-type="long"]').on('keydown', function(e) { + var regex = /^[0-9]*((?=[^.]|$))?$/; // allow only numbers [0-9] + if (!regex.test(e.currentTarget.value)) { + return false; + } + }); + that.$('input[data-type="long"]').on('keyup click', function(e) { + e.currentTarget.value = e.currentTarget.value; + var regex = /^[0-9]*((?=[^.]|$))?$/; // allow only numbers [0-9] + if (!regex.test(e.currentTarget.value)) { + var txtfld = e.currentTarget; + var newtxt = txtfld.value.slice(0, txtfld.value.length - 1); + txtfld.value = newtxt; + } + }); // IE9 allow input type number + }, onEntityChange: function(e, value) { this.modal.$el.find('button.ok').prop("disabled", false); var that = this, @@ -235,37 +257,31 @@ define(['require', }); } }); - that.$('input[data-type="long"]').each(function() { - if (!$(this).data('datepicker')) { - $(this).datetimepicker({ - format: 'DD MMMM YYYY, HH:mm', - showTodayButton: true, - showClose: true - }); - } - }); + that.longValidation(that); // IE9 allow input type number that.$('input[data-type="int"]').on('keydown', function(e) { - var regex = /^[0-9]*([.](?=[^.]|$))*(?:\.\d{1,2})?$/; // allow only numbers [0-9] + var regex = /^[0-9]*((?=[^.]|$))?$/; // allow only numbers [0-9] if (!regex.test(e.currentTarget.value)) { return false; } }); - if (that.ui.entityInputData.find('select.true,input.true').length === 0) { + if (that.ui.entityInputData.find('fieldset').length > 0 && that.ui.entityInputData.find('select.true,input.true').length === 0) { that.requiredAllToggle(that.ui.entityInputData.find('select.true,input.true').length === 0); that.ui.toggleRequired.prop('checked', true); - } // IE9 allow input type number that.$('input[data-type="int"]').on('keyup click', function(e) { e.currentTarget.value = e.currentTarget.value; - var regex = /^[0-9]*([.](?=[^.]|$))*(?:\.\d{1,2})?$/; // allow only numbers [0-9] + var regex = /^[0-9]*((?=[^.]|$))?$/; // allow only numbers [0-9] if (!regex.test(e.currentTarget.value)) { var txtfld = e.currentTarget; var newtxt = txtfld.value.slice(0, txtfld.value.length - 1); txtfld.value = newtxt; } }); + that.$('select[data-type="array<string>"]').each(function() { + that.addJsonSearchData(that.arryaType); + }); }, silent: true }); @@ -278,7 +294,6 @@ define(['require', if (value.isOptional == true) { alloptional = true; } - attributeInput += that.getContainer(value); }); if (attributeInput !== "") { @@ -298,7 +313,7 @@ define(['require', this.ui.entityInputData.find('div.true').hide(); } if (!('placeholder' in HTMLInputElement.prototype)) { - this.ui.entityInputData.find('input,select,textarea').placeholder(); + this.ui.entityInputData.find("input,select,textarea").placeholder(); } }, getContainer: function(value) { @@ -326,9 +341,6 @@ define(['require', if (value.typeName === "date" && dataValue) { entityValue = moment(dataValue).format("DD MMMM YYYY"); } - if (value.typeName === "long") { - entityValue = moment(dataValue).format("DD MMMM YYYY, HH:mm"); - } } } if (value.typeName === "string" || value.typeName === "long" || value.typeName === "int" || value.typeName === "boolean" || value.typeName === "date") { @@ -350,7 +362,7 @@ define(['require', changeDatatype = value.typeName; } else { if (value.typeName === "array<string>") { - changeDatatype = value.typeName; + this.arryaType = value.typeName; } else { changeDatatype = value.typeName.split('<')[1].split('>')[0]; } @@ -358,7 +370,7 @@ define(['require', $.extend(that.searchCollection.queryParams, { query: changeDatatype }); that.searchCollection.fetch({ reset: true }); return '<select class="form-control row-margin-bottom entityInputBox ' + (value.isOptional === true ? "false" : "true") + '" data-type="' + value.typeName + - '" data-key="' + value.name + '"data-id="entitySelectData" data-queryData="' + changeDatatype + '">' + (this.guid ? entityValue : "") + '</select>'; + '" data-key="' + value.name + '"data-id="entitySelectData" data-queryData="' + value.typeName + '">' + (this.guid ? entityValue : "") + '</select>'; } }, getSelect: function(value) { @@ -385,17 +397,13 @@ define(['require', }); } }); - that.$('input[data-type="long"]').each(function() { - if (!$(this).data('datepicker')) { - $(this).datetimepicker({ - format: 'DD MMMM YYYY, HH:mm', - showTodayButton: true, - showClose: true - }); - } - }); + that.longValidation(that); that.hideLoader(); } + if (that.ui.entityInputData.find('select.true,input.true').length === 0) { + that.requiredAllToggle(that.ui.entityInputData.find('select.true,input.true').length === 0); + that.ui.toggleRequired.prop('checked', true); + } that.$('select[data-type="boolean"]').each(function(value, key) { var dataKey = $(key).data('key'); if (that.entityData) { @@ -403,12 +411,10 @@ define(['require', this.value = setValue; } }); - }, silent: true }); }, - okButton: function() { var that = this; this.showLoader(); @@ -421,6 +427,7 @@ define(['require', if ($(this).val() && $(this).val().trim) { value = $(this).val().trim(); } + if ($(this).hasClass("true")) { if (value == "" || value == undefined) { if ($(this).data('select2')) { @@ -437,8 +444,8 @@ define(['require', var dataTypeEnitity = $(this).data('type'); var datakeyEntity = $(this).data('key'); var selectDataType = $(this).data('querydata'); - var pickKey = $(this).data('pickkey'); - if (typeof datakeyEntity === 'string' && datakeyEntity.indexOf("Time") > -1) { + // var pickKey = $(this).data('pickkey'); + if (typeof dataTypeEnitity === 'string' && datakeyEntity.indexOf("Time") > -1) { entityAttribute[datakeyEntity] = Date.parse($(this).val()); } else if (dataTypeEnitity == "string" || dataTypeEnitity === "long" || dataTypeEnitity === "int" || dataTypeEnitity === "boolean" || dataTypeEnitity == "date") { entityAttribute[datakeyEntity] = $(this).val(); @@ -450,35 +457,40 @@ define(['require', if (arrayEmptyValueCheck === "") { return; } - if (dataTypeEnitity === "array<string>" || dataTypeEnitity === "map<string,string>") { - parseData = value; + if (dataTypeEnitity === "array<string>") { + var parseData = value; } else { if (that.selectStoreCollection.length) { var parseData = value.map(function(val) { var temp = {} // I9 support; - temp[pickKey] = val; + temp['labelName'] = val; var valueData = that.selectStoreCollection.findWhere(temp).toJSON(); - valueData['guid'] = valueData.id; + valueData['guid'] = valueData.guid; return valueData; }) } } } else { - if (that.selectStoreCollection.length && pickKey) { - + if (that.selectStoreCollection.length) { var temp = {} // I9 support; - temp[pickKey] = $(this).val(); + temp['labelName'] = $(this).val(); var parseData = that.selectStoreCollection.findWhere(temp).toJSON(); - parseData['guid'] = parseData.id || parseData['$id$'].id; + parseData['guid'] = parseData.guid; } // Object but maptype - if (!pickKey) { - parseData = JSON.parse($(this).val()); + if (!temp['labelName']) { + try { + parseData = JSON.parse($(this).val()); + } catch (err) { + Utils.serverErrorHandler(); + } } } + } + if (parseData) { entityAttribute[datakeyEntity] = parseData - $(this).removeClass('errorClass'); } + $(this).removeClass('errorClass'); } catch (e) { $(this).addClass('errorClass'); that.validateError = e; @@ -510,11 +522,17 @@ define(['require', data: JSON.stringify(entityJson), type: this.guid ? "PUT" : "POST", success: function(model, response) { - that.callback(); that.modal.close(); Utils.notifySuccess({ content: "entity " + Messages[that.guid ? 'editSuccessMessage' : 'addSuccessMessage'] }); + if (that.guid && that.callback) { + that.callback(); + } else { + if (model.entitiesMutated && (model.entitiesMutated.CREATE || model.entitiesMutated.UPDATE)) { + that.setUrl('#!/detailPage/' + (model.entitiesMutated.CREATE ? model.entitiesMutated.CREATE[0].guid : model.entitiesMutated.UPDATE[0].guid), true); + } + } }, complete: function() { that.hideLoader(); @@ -522,6 +540,16 @@ define(['require', }); } }, + setUrl: function(url, create) { + Utils.setUrl({ + url: url, + mergeBrowserUrl: false, + trigger: true, + updateTabState: function() { + return { tagUrl: this.url, stateChanged: true }; + } + }); + }, showLoader: function() { this.$('.entityLoader').show(); this.$('.entityInputData').hide(); @@ -530,35 +558,35 @@ define(['require', this.$('.entityLoader').hide(); this.$('.entityInputData').show(); }, - addJsonSearchData: function(isError) { + addJsonSearchData: function(arrStingType) { var that = this, typename, str = ''; - if (isError) { - typename = isError.responseJSON.error.split(": ")[1]; + if (arrStingType) { + typename = arrStingType; } else { if (this.searchCollection.length) { - typename = this.searchCollection.first().get("$typeName$"); + typename = this.searchCollection.first().get("typeName"); this.selectStoreCollection.push(this.searchCollection.fullCollection.models); var labelName = ""; _.each(this.searchCollection.fullCollection.models, function(value, key) { - if (value.get("qualifiedName")) { - labelName = "qualifiedName"; - } else if (value.get("name")) { - labelName = "name"; - } else if (value.get("id")) { - labelName = "id"; + var obj = value.toJSON(); + + labelName = (_.escape(obj.attributes && obj.attributes.name ? obj.attributes.name : null) || _.escape(obj.displayText) || obj.guid); + value.set('labelName', labelName); + if (labelName) { + str += '<option>' + _.escape(labelName) + '</option>'; } - str += '<option>' + _.escape(value.get(labelName)) + '</option>'; }); + } else { + } } this.$('select[data-queryData="' + typename + '"]').html(str); - this.$('select[data-queryData="' + typename + '"]').attr('data-pickkey', labelName); - this.$('select[data-queryData="' + typename + '"]').each(function(value, key) { + $('select[data-id="' + 'entitySelectData' + '"]').each(function(value, key) { var keyData = $(this).data("key"); var typeData = $(this).data("type"); - var placeholderName = "Select a " + typename + " from the dropdown list"; + var placeholderName = "Select a " + typeData + " from the dropdown list"; var $this = $(this); $this.attr("multiple", ($this.data('type').indexOf("array") === -1 ? false : true)) if (that.guid) { @@ -567,15 +595,16 @@ define(['require', } var dataValue = that.entityData.get("attributes")[keyData]; that.selectStoreCollection.each(function(value) { + var obj = value.toJSON(); if (dataValue !== null && _.isArray(dataValue)) { _.each(dataValue, function(obj) { - if (obj.guid === value.get("id")) { - selectedValue.push(value.get("qualifiedName") || value.get("name") || value.get("id")); + if (obj.guid === value.attributes.guid) { + selectedValue.push(value.attributes.labelName); } }); } else if (dataValue !== null) { - if (dataValue.guid === value.get("id")) { - selectedValue.push(value.get("qualifiedName") || value.get("name") || value.get("id")); + if (dataValue.guid === value.attributes.guid) { + selectedValue.push(value.attributes.labelName); } } }); @@ -586,7 +615,9 @@ define(['require', var dataValue = that.entityData.get("attributes")[keyData]; if (dataValue !== null) { _.each(dataValue, function(obj) { - str += '<option>' + _.escape(obj) + '</option>'; + if (!_.isObject(obj)) { + str += '<option>' + _.escape(obj) + '</option>'; + } }); $this.html(str); } http://git-wip-us.apache.org/repos/asf/incubator-atlas/blob/a7870cde/dashboardv2/public/js/views/search/SearchDetailLayoutView.js ---------------------------------------------------------------------- diff --git a/dashboardv2/public/js/views/search/SearchDetailLayoutView.js b/dashboardv2/public/js/views/search/SearchDetailLayoutView.js index 0ed1c38..16e3fa1 100644 --- a/dashboardv2/public/js/views/search/SearchDetailLayoutView.js +++ b/dashboardv2/public/js/views/search/SearchDetailLayoutView.js @@ -43,7 +43,7 @@ define(['require', * @constructs */ initialize: function(options) { - _.extend(this, _.pick(options, 'globalVent', 'value')); + _.extend(this, _.pick(options, 'globalVent', 'value', 'initialView')); }, bindEvents: function() {}, onRender: function() { @@ -63,7 +63,8 @@ define(['require', if (that.RSearchResultLayoutView) { that.RSearchResultLayoutView.show(new SearchResultLayoutView({ value: value, - tag: that.tag + tag: that.tag, + initialView: that.initialView })); } }); http://git-wip-us.apache.org/repos/asf/incubator-atlas/blob/a7870cde/dashboardv2/public/js/views/search/SearchLayoutView.js ---------------------------------------------------------------------- diff --git a/dashboardv2/public/js/views/search/SearchLayoutView.js b/dashboardv2/public/js/views/search/SearchLayoutView.js index bdb71a6..958b23b 100644 --- a/dashboardv2/public/js/views/search/SearchLayoutView.js +++ b/dashboardv2/public/js/views/search/SearchLayoutView.js @@ -43,14 +43,7 @@ define(['require', searchBtn: '[data-id="searchBtn"]', clearSearch: '[data-id="clearSearch"]', typeLov: '[data-id="typeLOV"]', - refreshBtn: '[data-id="refreshBtn"]', - createEntity: "[data-id='createEntity']", - }, - - templateHelpers: function() { - return { - entityCreate: Globals.entityCreate - }; + refreshBtn: '[data-id="refreshBtn"]' }, /** ui events hash */ @@ -72,7 +65,6 @@ define(['require', events["click " + this.ui.clearSearch] = 'clearSearchData'; events["change " + this.ui.typeLov] = 'onChangeTypeList'; events["click " + this.ui.refreshBtn] = 'onRefreshButton'; - events["click " + this.ui.createEntity] = 'onClickCreateEntity'; return events; }, /** @@ -132,7 +124,9 @@ define(['require', return model.get('name').toLowerCase(); } this.typecollection.fullCollection.sort().each(function(model) { - str += '<option>' + _.escape(model.get("name")) + '</option>'; + if (model.get('category') == 'ENTITY') { + str += '<option>' + _.escape(model.get("name")) + '</option>'; + } }); that.ui.typeLov.html(str); }, @@ -257,20 +251,7 @@ define(['require', mergeBrowserUrl: false, trigger: true }); - }, - onClickCreateEntity: function(e) { - var that = this; - $(e.currentTarget).blur(); - require([ - 'views/entity/CreateEntityLayoutView' - ], function(CreateEntityLayoutView) { - var view = new CreateEntityLayoutView({ - callback: function() { - that.fetchCollection(); - } - }); - }); - }, + } }); return SearchLayoutView; }); http://git-wip-us.apache.org/repos/asf/incubator-atlas/blob/a7870cde/dashboardv2/public/js/views/search/SearchResultLayoutView.js ---------------------------------------------------------------------- diff --git a/dashboardv2/public/js/views/search/SearchResultLayoutView.js b/dashboardv2/public/js/views/search/SearchResultLayoutView.js index cbfe08e..5c2754b 100644 --- a/dashboardv2/public/js/views/search/SearchResultLayoutView.js +++ b/dashboardv2/public/js/views/search/SearchResultLayoutView.js @@ -58,9 +58,14 @@ define(['require', nextData: "[data-id='nextData']", pageRecordText: "[data-id='pageRecordText']", addAssignTag: "[data-id='addAssignTag']", - editEntityButton: "[data-id='editEntityButton']" + editEntityButton: "[data-id='editEntityButton']", + createEntity: "[data-id='createEntity']", + }, + templateHelpers: function() { + return { + entityCreate: Globals.entityCreate + }; }, - /** ui events hash */ events: function() { var events = {}; @@ -109,6 +114,7 @@ define(['require', events["click " + this.ui.nextData] = "onClicknextData"; events["click " + this.ui.previousData] = "onClickpreviousData"; events["click " + this.ui.editEntityButton] = "onClickEditEntity"; + events["click " + this.ui.createEntity] = 'onClickCreateEntity'; return events; }, /** @@ -116,7 +122,7 @@ define(['require', * @constructs */ initialize: function(options) { - _.extend(this, _.pick(options, 'globalVent', 'vent', 'value')); + _.extend(this, _.pick(options, 'globalVent', 'vent', 'value', 'initialView')); var pagination = ""; this.entityModel = new VEntity(); this.searchCollection = new VSearchList(); @@ -178,26 +184,32 @@ define(['require', }, this); }, onRender: function() { - var value = {}, - that = this; - if (this.value) { - value = this.value; - } else { - value = { - 'query': '', - 'searchType': 'fulltext' - }; - } - this.fetchCollection(value); - $('body').click(function(e) { - var iconEvnt = e.target.nodeName; - if (that.$('.popoverContainer').length) { - if ($(e.target).hasClass('tagDetailPopover') || iconEvnt == "I") { - return; + if (!this.initialView) { + var value = {}, + that = this; + if (this.value) { + value = this.value; + } else { + value = { + 'query': '', + 'searchType': 'fulltext' + }; + } + this.fetchCollection(value); + $('body').click(function(e) { + var iconEvnt = e.target.nodeName; + if (that.$('.popoverContainer').length) { + if ($(e.target).hasClass('tagDetailPopover') || iconEvnt == "I") { + return; + } + that.$('.popover.popoverTag').hide(); } - that.$('.popover.popoverTag').hide(); + }); + } else { + if (Globals.entityTypeConfList) { + this.$(".entityLink").show(); } - }); + } }, fetchCollection: function(value) { var that = this; @@ -264,13 +276,16 @@ define(['require', } var resultData = 'Results for <b>' + _.escape(that.searchCollection.queryParams.query) + '</b>'; var multiAssignDataTag = '<a href="javascript:void(0)" class="inputAssignTag multiSelectTag assignTag" style="display:none" data-id="addAssignTag"><i class="fa fa-plus"></i>' + " " + 'Assign Tag</a>'; + var resultText = that.searchCollection.queryParams.query; + var multiAssignDataTerm = "", + createEntityTag = ""; if (Globals.taxonomy) { - var multiAssignDataTerm = '<a href="javascript:void(0)" class="inputAssignTag multiSelect" style="display:none" data-id="addTerm"><i class="fa fa-folder-o"></i>' + " " + 'Assign Term</a>'; - that.$('.searchResult').html(resultData + multiAssignDataTerm + multiAssignDataTag); - } else { - that.$('.searchResult').html(resultData + multiAssignDataTag); + multiAssignDataTerm = '<a href="javascript:void(0)" class="inputAssignTag multiSelect" style="display:none" data-id="addTerm"><i class="fa fa-folder-o"></i>' + " " + 'Assign Term</a>'; } - + if (Globals.entityCreate && (resultText.indexOf("\`") != 0) && Globals.entityTypeConfList) { + createEntityTag = "<p>If you do not find the entity in search result below then you can" + '<a href="javascript:void(0)" data-id="createEntity"> create new entity</a></p>'; + } + that.$('.searchResult').html(resultData + multiAssignDataTag + multiAssignDataTerm + createEntityTag); }, silent: true, reset: true @@ -341,7 +356,13 @@ define(['require', return '<div class="readOnly readOnlyLink">' + nameHtml + '</div>'; } else { if (Globals.entityUpdate) { - nameHtml += '<button title="Edit" data-id="editEntityButton" data-giud= "' + obj.guid + '" class="btn btn-atlasAction btn-atlas editBtn"><i class="fa fa-pencil"></i></button>' + if (Globals.entityTypeConfList && _.isEmptyArray(Globals.entityTypeConfList)) { + nameHtml += '<button title="Edit" data-id="editEntityButton" data-giud= "' + obj.guid + '" class="btn btn-atlasAction btn-atlas editBtn"><i class="fa fa-pencil"></i></button>' + } else { + if (_.contains(Globals.entityTypeConfList, obj.typeName)) { + nameHtml += '<button title="Edit" data-id="editEntityButton" data-giud= "' + obj.guid + '" class="btn btn-atlasAction btn-atlas editBtn"><i class="fa fa-pencil"></i></button>' + } + } } return nameHtml; } @@ -606,6 +627,19 @@ define(['require', } }); }); + }, + onClickCreateEntity: function(e) { + var that = this; + $(e.currentTarget).blur(); + require([ + 'views/entity/CreateEntityLayoutView' + ], function(CreateEntityLayoutView) { + var view = new CreateEntityLayoutView({ + callback: function() { + that.fetchCollection(); + } + }); + }); } }); return SearchResultLayoutView; http://git-wip-us.apache.org/repos/asf/incubator-atlas/blob/a7870cde/dashboardv2/public/js/views/tag/addTagModalView.js ---------------------------------------------------------------------- diff --git a/dashboardv2/public/js/views/tag/addTagModalView.js b/dashboardv2/public/js/views/tag/addTagModalView.js index 7317a95..3d00caf 100644 --- a/dashboardv2/public/js/views/tag/addTagModalView.js +++ b/dashboardv2/public/js/views/tag/addTagModalView.js @@ -98,8 +98,8 @@ define(['require', }); } if (obj.skipEntity.length) { - var text = "<b>" + obj.skipEntity.join(', ') + - "</b> <br/> entities selected have already been associated with <b>" + tagName + + var text = "<b>" + obj.skipEntity.length + " of " + that.multiple.length + + "</b> entities selected have already been associated with <b>" + tagName + "</b> tag, Do you want to associate the tag with other entities ?", removeCancelButton = false; if ((obj.skipEntity.length + obj.deletedEntity.length) === that.multiple.length) { http://git-wip-us.apache.org/repos/asf/incubator-atlas/blob/a7870cde/webapp/src/main/java/org/apache/atlas/web/resources/AdminResource.java ---------------------------------------------------------------------- diff --git a/webapp/src/main/java/org/apache/atlas/web/resources/AdminResource.java b/webapp/src/main/java/org/apache/atlas/web/resources/AdminResource.java index 54c46a8..3bdcc87 100755 --- a/webapp/src/main/java/org/apache/atlas/web/resources/AdminResource.java +++ b/webapp/src/main/java/org/apache/atlas/web/resources/AdminResource.java @@ -48,6 +48,7 @@ import javax.ws.rs.core.MediaType; import javax.ws.rs.core.Response; import java.util.Collection; import java.util.HashSet; +import java.util.List; import java.util.Set; /** @@ -65,6 +66,8 @@ public class AdminResource { private static final String isTaxonomyEnabled = "atlas.feature.taxonomy.enable"; private static final String isEntityUpdateAllowed = "atlas.entity.update.allowed"; private static final String isEntityCreateAllowed = "atlas.entity.create.allowed"; + private static final String editableEntityTypes = "atlas.ui.editable.entity.types"; + private static final String DEFAULT_EDITABLE_ENTITY_TYPES = "hdfs_path,hdfs_path,hbase_table,hbase_column,hbase_column_family,kafka_topic"; private Response version; private ServiceState serviceState; private MetricsService metricsService; @@ -213,6 +216,7 @@ public class AdminResource { responseData.put(isTaxonomyEnabled, enableTaxonomy); responseData.put(isEntityUpdateAllowed, isEntityUpdateAccessAllowed); responseData.put(isEntityCreateAllowed, isEntityCreateAccessAllowed); + responseData.put(editableEntityTypes, getEditableEntityTypes(configProperties)); responseData.put("userName", userName); responseData.put("groups", groups); @@ -244,4 +248,30 @@ public class AdminResource { return metrics; } + + private String getEditableEntityTypes(PropertiesConfiguration config) { + String ret = DEFAULT_EDITABLE_ENTITY_TYPES; + + if (config.containsKey(editableEntityTypes)) { + Object value = config.getProperty(editableEntityTypes); + + if (value instanceof String) { + ret = (String)value; + } else if (value instanceof Collection) { + StringBuilder sb = new StringBuilder(); + + for (Object elem : ((Collection)value)) { + if (sb.length() > 0) { + sb.append(","); + } + + sb.append(elem.toString()); + } + + ret = sb.toString(); + } + } + + return ret; + } }
