You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@atlas.apache.org by kb...@apache.org on 2020/02/21 06:26:32 UTC
[atlas] 01/03: ATLAS-3554 : UI: changes to
display/add/update/delete namespace attributes for entities in entity
details page
This is an automated email from the ASF dual-hosted git repository.
kbhatt pushed a commit to branch branch-2.0
in repository https://gitbox.apache.org/repos/asf/atlas.git
commit bad7a89e605beca3ca84f9aa38f00a0a09698693
Author: kevalbhatt <kb...@apache.org>
AuthorDate: Fri Feb 14 17:34:53 2020 +0530
ATLAS-3554 : UI: changes to display/add/update/delete namespace attributes for entities in entity details page
(cherry picked from commit 70ebb22829a4dae8f06031b045f4848a4c22fc05)
---
dashboardv3/public/css/scss/common.scss | 1 +
dashboardv3/public/css/scss/panel.scss | 2 +-
dashboardv3/public/js/models/VEntity.js | 10 +-
dashboardv3/public/js/modules/Helpers.js | 6 +
.../detail_page/DetailPageLayoutView_tmpl.html | 1 +
.../entity/EntityNameSpaceItemView_tmpl.html | 40 +++
.../templates/entity/EntityNameSpaceView_tmpl.html | 44 +++
.../entity/EntityUserDefineItemView_tmpl.html | 2 +-
dashboardv3/public/js/utils/UrlLinks.js | 5 +
.../js/views/detail_page/DetailPageLayoutView.js | 13 +-
.../js/views/entity/EntityNameSpaceItemView.js | 297 +++++++++++++++++++++
.../public/js/views/entity/EntityNameSpaceView.js | 251 +++++++++++++++++
12 files changed, 667 insertions(+), 5 deletions(-)
diff --git a/dashboardv3/public/css/scss/common.scss b/dashboardv3/public/css/scss/common.scss
index aa20b70..016c8bf 100644
--- a/dashboardv3/public/css/scss/common.scss
+++ b/dashboardv3/public/css/scss/common.scss
@@ -248,6 +248,7 @@ pre {
.custom-col-1 {
width: 39%;
+ margin-bottom: 10px;
}
.custom-col-2 {
diff --git a/dashboardv3/public/css/scss/panel.scss b/dashboardv3/public/css/scss/panel.scss
index 9d38a3e..66adc26 100644
--- a/dashboardv3/public/css/scss/panel.scss
+++ b/dashboardv3/public/css/scss/panel.scss
@@ -159,9 +159,9 @@
.panel-default.custom-panel>.panel-actions {
float: right;
margin-top: 15px;
+ margin-right: 10px;
button {
- margin-right: 10px;
margin-top: -4px;
}
}
diff --git a/dashboardv3/public/js/models/VEntity.js b/dashboardv3/public/js/models/VEntity.js
index 84a185f..e9ea1f3 100644
--- a/dashboardv3/public/js/models/VEntity.js
+++ b/dashboardv3/public/js/models/VEntity.js
@@ -107,7 +107,15 @@ define(['require',
deleteNameSpace: function(options) {
var url = UrlLinks.nameSpaceUpdateUrl(options.typeName);
return this.constructor.nonCrudOperation.call(this, url, 'DELETE', options);
- }
+ },
+ saveNamespaceEntity: function(guid, options) {
+ var url = UrlLinks.entitiesNamespaceApiUrl(guid);
+ options = _.extend({
+ contentType: 'application/json',
+ dataType: 'json'
+ }, options);
+ return this.constructor.nonCrudOperation.call(this, url, 'POST', options);
+ },
}, {});
return VEntity;
});
\ No newline at end of file
diff --git a/dashboardv3/public/js/modules/Helpers.js b/dashboardv3/public/js/modules/Helpers.js
index 2f36a0d..7ef5f25 100644
--- a/dashboardv3/public/js/modules/Helpers.js
+++ b/dashboardv3/public/js/modules/Helpers.js
@@ -89,6 +89,12 @@ define(['require',
case '>=':
return (v1 >= v2) ? options.fn(this) : options.inverse(this);
break;
+ case 'isEmpty':
+ return (_.isEmpty(v1)) ? options.fn(this) : options.inverse(this);
+ break;
+ case 'has':
+ return (_.has(v1, v2)) ? options.fn(this) : options.inverse(this);
+ break;
default:
return options.inverse(this);
break;
diff --git a/dashboardv3/public/js/templates/detail_page/DetailPageLayoutView_tmpl.html b/dashboardv3/public/js/templates/detail_page/DetailPageLayoutView_tmpl.html
index 7c5a43e..1eb68e3 100644
--- a/dashboardv3/public/js/templates/detail_page/DetailPageLayoutView_tmpl.html
+++ b/dashboardv3/public/js/templates/detail_page/DetailPageLayoutView_tmpl.html
@@ -79,6 +79,7 @@
<div class="col-md-6">
<div id="r_entityUserDefineView"></div>
<div id="r_entityLabelDefineView"></div>
+ <div id="r_entityNameSpaceView"></div>
</div>
</div>
</div>
diff --git a/dashboardv3/public/js/templates/entity/EntityNameSpaceItemView_tmpl.html b/dashboardv3/public/js/templates/entity/EntityNameSpaceItemView_tmpl.html
new file mode 100644
index 0000000..d030ee6
--- /dev/null
+++ b/dashboardv3/public/js/templates/entity/EntityNameSpaceItemView_tmpl.html
@@ -0,0 +1,40 @@
+<!--
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+-->
+{{#ifCond model "has" "isNew"}}
+<td class="custom-col-1">
+ {{{callmyfunction getNamespaceDroupdown nameSpaceCollection}}}
+</td>
+<td class="custom-col-0"> : </td>
+<td class="custom-col-1" data-id="value">
+ <input type="text" data-key disabled class="form-control">
+</td>
+<td class="custom-col-2 btn-group">
+ <button class="btn btn-default btn-sm" data-id="deleteItem">
+ <i class="fa fa-minus"> </i>
+ </button>
+ <button class="btn btn-default btn-sm" data-id="addItem">
+ <i class="fa fa-plus"> </i>
+ </button>
+</td>
+{{else}}
+<hr />
+<ul class="namespace-tree-parent">
+ <li>{{model.__internal_UI_nameSpaceName}}</li>
+ <li class="namespace-tree-child" data-id="namespaceTreeChild">
+ </li>
+</ul>
+{{/ifCond}}
\ No newline at end of file
diff --git a/dashboardv3/public/js/templates/entity/EntityNameSpaceView_tmpl.html b/dashboardv3/public/js/templates/entity/EntityNameSpaceView_tmpl.html
new file mode 100644
index 0000000..6b622d7
--- /dev/null
+++ b/dashboardv3/public/js/templates/entity/EntityNameSpaceView_tmpl.html
@@ -0,0 +1,44 @@
+<!--
+ * 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 panel-default custom-panel expand_collapse_panel-icon" data-id="namespace">
+ <div class="panel-heading" data-toggle="collapse" href="#namespaceCollapse" aria-expanded="false" style="width: 70%;">
+ <h4 class="panel-title">
+ <a>Namespaces</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">
+ <button class="btn btn-action btn-sm" title="" data-id="addNameSpace">Add</button>
+ <button class="btn btn-action btn-sm" style="display: none;" data-id="saveNameSpace">Save</button>
+ <button class="btn btn-action btn-sm" style="display: none;" data-id="cancel">Cancel</button>
+ </div>
+ <div id="namespaceCollapse" class="panel-collapse collapse">
+ <div class="panel-body">
+ <div data-id="namespaceTree"></div>
+ <div class="editBox" style="display: none;">
+ <div class="form-group">
+ <a href="javascript:void(0)" class="btn btn-action btn-sm" data-id="addItem" data-type="addAttrButton">Add New Attribute</a>
+ </div>
+ <table class="custom-table">
+ <tbody data-id="itemView"></tbody>
+ </table>
+ </div>
+ </div>
+ </div>
+</div>
\ No newline at end of file
diff --git a/dashboardv3/public/js/templates/entity/EntityUserDefineItemView_tmpl.html b/dashboardv3/public/js/templates/entity/EntityUserDefineItemView_tmpl.html
index 439943d..74dcd91 100644
--- a/dashboardv3/public/js/templates/entity/EntityUserDefineItemView_tmpl.html
+++ b/dashboardv3/public/js/templates/entity/EntityUserDefineItemView_tmpl.html
@@ -26,7 +26,7 @@
<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">
+ <td class="custom-col-2 btn-group">
<button class="btn btn-default btn-sm" title="" data-index={{@index}} data-id="deleteItem">
<i class="fa fa-minus"> </i>
</button>
diff --git a/dashboardv3/public/js/utils/UrlLinks.js b/dashboardv3/public/js/utils/UrlLinks.js
index 6a09d31..2bbe679 100644
--- a/dashboardv3/public/js/utils/UrlLinks.js
+++ b/dashboardv3/public/js/utils/UrlLinks.js
@@ -99,6 +99,11 @@ define(['require', 'utils/Enums', 'utils/Utils', 'underscore'], function(require
return this.baseUrlV2 + '/entity/bulk/classification';
}
},
+ entitiesNamespaceApiUrl: function(guid) {
+ if (guid) {
+ return this.baseUrlV2 + '/entity/guid/' + guid + '/namespaces?isOverwrite=true';
+ }
+ },
entityCollectionaudit: function(guid) {
return this.baseUrlV2 + '/entity/' + guid + '/audit';
},
diff --git a/dashboardv3/public/js/views/detail_page/DetailPageLayoutView.js b/dashboardv3/public/js/views/detail_page/DetailPageLayoutView.js
index ccb2317..c2511b9 100644
--- a/dashboardv3/public/js/views/detail_page/DetailPageLayoutView.js
+++ b/dashboardv3/public/js/views/detail_page/DetailPageLayoutView.js
@@ -46,7 +46,8 @@ define(['require',
RProfileLayoutView: "#r_profileLayoutView",
RRelationshipLayoutView: "#r_relationshipLayoutView",
REntityUserDefineView: "#r_entityUserDefineView",
- REntityLabelDefineView: "#r_entityLabelDefineView"
+ REntityLabelDefineView: "#r_entityLabelDefineView",
+ REntityNameSpaceView: "#r_entityNameSpaceView"
},
/** ui selector cache */
ui: {
@@ -120,7 +121,7 @@ define(['require',
* @constructs
*/
initialize: function(options) {
- _.extend(this, _.pick(options, 'value', 'collection', 'id', 'entityDefCollection', 'typeHeaders', 'enumDefCollection', 'classificationDefCollection', 'glossaryCollection', 'searchVent'));
+ _.extend(this, _.pick(options, 'value', 'collection', 'id', 'entityDefCollection', 'typeHeaders', 'enumDefCollection', 'classificationDefCollection', 'glossaryCollection', 'nameSpaceCollection', 'searchVent'));
$('body').addClass("detail-page");
},
bindEvents: function() {
@@ -244,6 +245,7 @@ define(['require',
enumDefCollection: this.enumDefCollection,
classificationDefCollection: this.classificationDefCollection,
glossaryCollection: this.glossaryCollection,
+ nameSpaceCollection: this.nameSpaceCollection,
searchVent: this.searchVent,
attributeDefs: (function() {
return that.getEntityDef(collectionJSON);
@@ -253,6 +255,7 @@ define(['require',
this.renderEntityDetailTableLayoutView(obj);
this.renderEntityUserDefineView(obj);
this.renderEntityLabelDefineView(obj);
+ this.renderEntityNameSpaceView(obj);
this.renderRelationshipLayoutView(obj);
this.renderAuditTableLayoutView(obj);
this.renderTagTableLayoutView(obj);
@@ -512,6 +515,12 @@ define(['require',
that.REntityLabelDefineView.show(new EntityLabelDefineView(obj));
});
},
+ renderEntityNameSpaceView: function(obj) {
+ var that = this;
+ require(['views/entity/EntityNameSpaceView'], function(EntityNameSpaceView) {
+ that.REntityNameSpaceView.show(new EntityNameSpaceView(obj));
+ });
+ },
renderTagTableLayoutView: function(obj) {
var that = this;
require(['views/tag/TagDetailTableLayoutView'], function(TagDetailTableLayoutView) {
diff --git a/dashboardv3/public/js/views/entity/EntityNameSpaceItemView.js b/dashboardv3/public/js/views/entity/EntityNameSpaceItemView.js
new file mode 100644
index 0000000..9982e14
--- /dev/null
+++ b/dashboardv3/public/js/views/entity/EntityNameSpaceItemView.js
@@ -0,0 +1,297 @@
+/*
+ * 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/EntityNameSpaceItemView_tmpl',
+ 'moment',
+ 'daterangepicker'
+], function(require, Backbone, EntityNameSpaceItemViewTmpl, moment) {
+ 'use strict';
+
+ return Backbone.Marionette.ItemView.extend({
+ _viewName: 'EntityNameSpaceItemView',
+
+ template: EntityNameSpaceItemViewTmpl,
+
+ templateHelpers: function() {
+ return {
+ editMode: this.editMode,
+ entity: this.entity,
+ getValue: this.getValue.bind(this),
+ getNamespaceDroupdown: this.getNamespaceDroupdown.bind(this),
+ nameSpaceCollection: this.nameSpaceCollection.fullCollection.toJSON(),
+ model: this.model.toJSON()
+ }
+ },
+ tagName: 'tr',
+ className: "custom-tr",
+
+ /** Layout sub regions */
+ regions: {},
+
+ /** ui selector cache */
+ ui: {
+ keyEl: "[data-id='key']",
+ valueEl: "[data-type='value']",
+ addItem: "[data-id='addItem']",
+ deleteItem: "[data-id='deleteItem']",
+ editMode: "[data-id='editMode']"
+ },
+ /** ui events hash */
+ events: function() {
+ var events = {};
+ events["click " + this.ui.deleteItem] = 'onDeleteItem';
+ events["change " + this.ui.keyEl] = 'onAttrChange';
+ return events;
+ },
+
+ /**
+ * intialize a new EntityNameSpaceItemView Layout
+ * @constructs
+ */
+ initialize: function(options) {
+ _.extend(this, options);
+ },
+ onRender: function() {
+ var that = this;
+ this.ui.keyEl.val("");
+ this.ui.keyEl.select2({ placeholder: "Select Attribute" });
+
+ if (this.editMode && (!this.model.has("isNew"))) {
+ this.getEditNamespaceEl();
+ }
+ this.initializeElement();
+ this.bindEvent();
+ },
+ initializeElement: function() {},
+ bindEvent: function() {
+ var that = this;
+ if (this.editMode) {
+ this.listenTo(this.model.collection, 'destroy unset:attr', function() {
+ if (this.model.has("isNew")) {
+ this.render();
+ }
+ });
+ this.listenTo(this.model.collection, 'selected:attr', function(value, model) {
+ if (model.cid !== this.model.cid && this.model.has("isNew")) {
+ var $select2el = that.$el.find('.custom-col-1:first-child>select[data-id="key"]');
+ $select2el.find('option[value="' + value + '"]').remove();
+ var select2val = $select2el.select2("val");
+ $select2el.select2({ placeholder: "Select Attribute" });
+ if (this.model.keys().length <= 2) {
+ $select2el.val("").trigger("change", true);
+ }
+ }
+ });
+ this.$el.off("change", ".custom-col-1[data-id='value']>[data-key]").on("change", ".custom-col-1[data-id='value']>[data-key]", function(e) {
+ var key = $(this).data("key"),
+ namespace = $(this).data("namespace"),
+ typeName = $(this).data("typename"),
+ multi = $(this).data("multi"),
+ updateObj = that.model.toJSON();
+ if (_.isUndefinedNull(updateObj[key])) {
+ updateObj[key] = { value: null, typeName: typeName };
+ }
+ updateObj[key].value = multi ? $(this).select2("val") : e.currentTarget.value;
+ if (!that.model.has("__internal_UI_nameSpaceName")) {
+ updateObj["__internal_UI_nameSpaceName"] = namespace;
+ }
+ if (typeName === "date") {
+ updateObj[key].value = new Date(updateObj[key].value).getTime()
+ }
+ that.model.set(updateObj);
+ });
+ this.$el.on('keypress', '.select2_only_number .select2-search__field', function() {
+ $(this).val($(this).val().replace(/[^\d].+/, ""));
+ if ((event.which < 48 || event.which > 57)) {
+ event.preventDefault();
+ }
+ });
+ }
+ },
+ getAttrElement: function(options) {
+ var that = this,
+ returnEL = "N/A";
+ if (options) {
+ var key = options.key,
+ typeName = options.val.typeName || "",
+ val = options.val.value,
+ isMultiValued = typeName && typeName.indexOf("array<") === 0,
+ namespace = options.namespace,
+ allowOnlyNum = false;
+ var elType = isMultiValued ? "select" : "input";
+ if (!_.isEmpty(val)) {
+ val = _.escape(val);
+ }
+ if (typeName === "boolean") {
+ val = String(val);
+ }
+ if (typeName === "date" && _.isNumber(val)) {
+ val = moment(val).format("MM/DD/YYYY");
+ }
+ if (typeName.indexOf("string") > -1) {
+ returnEL = '<' + elType + ' type="text" data-key="' + key + '" data-namespace="' + namespace + '" data-typename="' + typeName + '" data-multi="' + isMultiValued + '" multiple="' + isMultiValued + '" placeholder="Enter String" class="form-control" ' + (!_.isUndefinedNull(val) ? 'value="' + val + '"' : "") + '></' + elType + '>';
+ } else if (typeName === "boolean") {
+ returnEL = '<select data-key="' + key + '" data-namespace="' + namespace + '" data-typename="' + typeName + '" class="form-control"><option value="">--Select Value--</option><option value="true" ' + (!_.isUndefinedNull(val) && val == "true" ? "selected" : "") + '>true</option><option value="false" ' + (!_.isUndefinedNull(val) && val == "false" ? "selected" : "") + '>false</option></select>';
+ } else if (typeName === "date") {
+ returnEL = '<input type="text" data-key="' + key + '" data-namespace="' + namespace + '" data-typename="' + typeName + '" data-type="date" class="form-control" ' + (!_.isUndefinedNull(val) ? 'value="' + val + '"' : "") + '>'
+ setTimeout(function() {
+ var dateObj = { "singleDatePicker": true, "showDropdowns": true };
+ that.$el.find('input[data-type="date"]').daterangepicker(dateObj);
+ }, 0);
+ } else if (typeName === "byte" || typeName === "short" || typeName.indexOf("int") > -1 || typeName.indexOf("float") > -1 || typeName === "double" || typeName === "long") {
+ allowOnlyNum = true;
+ returnEL = '<' + elType + ' data-key="' + key + '" data-namespace="' + namespace + '" data-typename="' + typeName + '" type="number" data-multi="' + isMultiValued + '" multiple="' + isMultiValued + '" placeholder="Enter Number" class="form-control" ' + (!_.isUndefinedNull(val) ? 'value="' + val + '"' : "") + '></' + elType + '>';
+ } else if (typeName) {
+ var foundEnumType = this.enumDefCollection.fullCollection.find({ name: typeName });
+ if (foundEnumType) {
+ var enumOptions = "";
+ _.forEach(foundEnumType.get("elementDefs"), function(obj) {
+ enumOptions += '<option value="' + obj.value + '">' + obj.value + '</option>'
+ });
+ returnEL = '<select data-key="' + key + '" data-namespace="' + namespace + '" data-typename="' + typeName + '">' + enumOptions + '</select>';
+ }
+ setTimeout(function() {
+ var selectEl = that.$el.find('.custom-col-1[data-id="value"] select[data-key="' + key + '"]');
+ selectEl.val((val || ""));
+ selectEl.select2();
+ }, 0);
+ }
+ if (isMultiValued) {
+ setTimeout(function() {
+ var selectEl = that.$el.find('.custom-col-1[data-id="value"] select[data-key="' + key + '"][data-multi="true"]');
+ var data = val && val.split(",") || [];
+ if (allowOnlyNum) {
+ selectEl.parent().addClass("select2_only_number");
+ }
+ selectEl.select2({ tags: true, multiple: true, data: data });
+ selectEl.val(data).trigger("change");
+ }, 0);
+ }
+ }
+ return returnEL;
+ },
+ onAttrChange: function(e, manual) {
+ var key = e.currentTarget.value.split(":");
+ if (key.length && key.length === 3) {
+ var valEl = $(e.currentTarget).parent().siblings(".custom-col-1"),
+ hasModalData = this.model.get(key[1]);
+ if (!hasModalData) {
+ var tempObj = {
+ "__internal_UI_nameSpaceName": key[0]
+ };
+ if (this.model.has("isNew")) {
+ tempObj["isNew"] = true;
+ }
+ tempObj[key[1]] = null;
+ this.model.clear({ silent: true }).set(tempObj)
+ }
+ valEl.html(this.getAttrElement({ namespace: key[0], key: key[1], val: hasModalData ? hasModalData : { typeName: key[2] } }));
+ if (manual === undefined) {
+ this.model.collection.trigger("selected:attr", e.currentTarget.value, this.model);
+ }
+ }
+ },
+ getValue: function(value, key, namespaceName) {
+ var typeName = value.typeName,
+ value = value.value;
+ if (typeName === "date") {
+ return moment(value).format("MM/DD/YYYY");
+ } else {
+ return value;
+ }
+ },
+ getNamespaceDroupdown: function(nameSpaceCollection) {
+ var optgroup = "";
+ var that = this;
+ var model = that.model.omit(["isNew", "__internal_UI_nameSpaceName"]),
+ keys = _.keys(model),
+ isSelected = false,
+ selectdVal = null;
+ if (keys.length === 1) {
+ isSelected = true;
+ }
+ _.each(nameSpaceCollection, function(obj) {
+ var options = "";
+ if (obj.attributeDefs.length) {
+ _.each(obj.attributeDefs, function(attrObj) {
+ var entityNamespace = that.model.collection.filter({ __internal_UI_nameSpaceName: obj.name }),
+ hasAttr = false;
+ if (entityNamespace) {
+ var found = entityNamespace.find(function(obj) {
+ return obj.attributes.hasOwnProperty(attrObj.name);
+ });
+ if (found) {
+ hasAttr = true;
+ }
+ }
+ if ((isSelected && keys[0] === attrObj.name) || !(hasAttr) && attrObj.options.applicableEntityTypes.indexOf('"' + that.entity.typeName + '"') > -1) {
+ var value = obj.name + ":" + attrObj.name + ":" + attrObj.typeName;
+ if (isSelected && keys[0] === attrObj.name) { selectdVal = value };
+ options += '<option value="' + value + '">' + attrObj.name + ' (' + _.escape(attrObj.typeName) + ')</option>';
+ }
+ });
+ if (options.length) {
+ optgroup += '<optgroup label="' + obj.name + '">' + options + '</optgroup>';
+ }
+ }
+ });
+
+ setTimeout(function() {
+ if (selectdVal) {
+ that.$el.find('.custom-col-1:first-child>select[data-id="key"]').val(selectdVal).trigger("change", true);
+ } else {
+ that.$el.find('.custom-col-1:first-child>select[data-id="key"]').val("").trigger("change", true);
+ }
+ }, 0);
+ return '<select data-id="key">' + optgroup + '</select>';
+ },
+ getEditNamespaceEl: function() {
+ var that = this,
+ trs = "";
+ _.each(this.model.attributes, function(val, key) {
+ if (key !== "__internal_UI_nameSpaceName" && key !== "isNew") {
+ var td = '<td class="custom-col-1" data-key=' + key + '>' + key + '</td><td class="custom-col-0">:</td><td class="custom-col-1" data-id="value">' + that.getAttrElement({ namespace: that.model.get("__internal_UI_nameSpaceName"), key: key, val: val }) + '</td>';
+
+ td += '<td class="custom-col-2 btn-group">' +
+ '<button class="btn btn-default btn-sm" data-key="' + key + '" data-id="deleteItem">' +
+ '<i class="fa fa-times"> </i>' +
+ '</button></td>';
+ trs += "<tr>" + td + "</tr>";
+ }
+ })
+ this.$("[data-id='namespaceTreeChild']").html("<table class='custom-table'>" + trs + "</table>");
+ },
+ onDeleteItem: function(e) {
+ var key = $(e.currentTarget).data("key");
+ if (this.model.has(key)) {
+ if (this.model.keys().length === 2) {
+ this.model.destroy();
+ } else {
+ this.model.unset(key);
+ if (!this.model.has("isNew")) {
+ this.$el.find("tr>td:first-child[data-key='" + key + "']").parent().remove()
+ }
+ this.model.collection.trigger("unset:attr");
+ }
+ } else {
+ this.model.destroy();
+ }
+ }
+ });
+});
\ No newline at end of file
diff --git a/dashboardv3/public/js/views/entity/EntityNameSpaceView.js b/dashboardv3/public/js/views/entity/EntityNameSpaceView.js
new file mode 100644
index 0000000..bbec0f7
--- /dev/null
+++ b/dashboardv3/public/js/views/entity/EntityNameSpaceView.js
@@ -0,0 +1,251 @@
+/**
+ * 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/EntityNameSpaceView_tmpl",
+ "views/entity/EntityNameSpaceItemView",
+ "models/VEntity",
+ "utils/Utils",
+ "utils/Enums",
+ "utils/Messages",
+ "utils/CommonViewFunction",
+ 'moment'
+], function(require, Backbone, EntityNameSpaceViewTmpl, EntityNameSpaceItemView, VEntity, Utils, Enums, Messages, CommonViewFunction, moment) {
+ "use strict";
+
+ return Backbone.Marionette.CompositeView.extend({
+ _viewName: "EntityNameSpaceView",
+ template: EntityNameSpaceViewTmpl,
+ childView: EntityNameSpaceItemView,
+ childViewContainer: "[data-id='itemView']",
+ childViewOptions: function() {
+ return {
+ editMode: this.editMode,
+ entity: this.entity,
+ nameSpaceCollection: this.nameSpaceCollection,
+ enumDefCollection: this.enumDefCollection
+ };
+ },
+ /** ui selector cache */
+ ui: {
+ addItem: "[data-id='addItem']",
+ addNameSpace: "[data-id='addNameSpace']",
+ saveNameSpace: "[data-id='saveNameSpace']",
+ namespaceTree: "[data-id='namespaceTree']",
+ cancel: "[data-id='cancel']"
+ },
+ events: function() {
+ var events = {};
+ events["click " + this.ui.addItem] = 'createNameElement';
+ events["click " + this.ui.addNameSpace] = "onAddNameSpace";
+ events["click " + this.ui.saveNameSpace] = "onSaveNameSpace";
+ events["click " + this.ui.cancel] = "onCancel";
+ return events;
+ },
+ initialize: function(options) {
+ var that = this;
+ _.extend(this, _.pick(options, "entity", "nameSpaceCollection", "enumDefCollection", "guid", "fetchCollection"));
+ this.editMode - false;
+ this.$("editBox").hide();
+ var nameSpaceSet = {};
+ this.treeData = [];
+ this.actualCollection = new Backbone.Collection(
+ _.map(this.entity.namespaceAttributes, function(val, key) {
+ var foundNameSpace = that.nameSpaceCollection.fullCollection.find({ name: key });
+ var tempData = {
+ text: key,
+ name: key,
+ parent: "#",
+ icon: "fa fa-folder-o",
+ children: []
+ }
+ if (foundNameSpace) {
+ var attributeDefs = foundNameSpace.get("attributeDefs");
+ _.each(val, function(aVal, aKey) {
+ var foundAttr = _.find(attributeDefs, function(o) {
+ return o.name === aKey
+ });
+ if (foundAttr) {
+ var treVal = aKey + " : " + (foundAttr.typeName === "date" ? moment(aVal).format("MM/DD/YYYY") : aVal);
+ tempData.children.push({
+ text: treVal,
+ name: treVal,
+ icon: "fa fa-file-o",
+ children: []
+ })
+ val[aKey] = { value: aVal, typeName: foundAttr.typeName };
+ }
+ })
+ }
+ that.treeData.push(tempData);
+ return _.extend({}, val, { __internal_UI_nameSpaceName: key });
+ }));
+ this.collection = new Backbone.Collection();
+ this.entityModel = new VEntity();
+ },
+ updateToActualData: function(options) {
+ var silent = options && options.silent || false;
+ this.collection.reset(this.actualCollection.toJSON(), { silent: silent });
+ },
+ onAddNameSpace: function() {
+ this.ui.addNameSpace.hide();
+ this.ui.saveNameSpace.show();
+ this.ui.cancel.show();
+ this.editMode = true;
+ this.ui.namespaceTree.hide();
+ this.$(".editBox").show();
+ this.updateToActualData({ silent: true });
+ if (this.collection.length === 0) {
+ this.createNameElement();
+ } else {
+ this.collection.trigger("reset");
+ }
+ this.panelOpenClose();
+ },
+ onCancel: function() {
+ this.ui.cancel.hide();
+ this.ui.saveNameSpace.hide();
+ this.ui.addNameSpace.show();
+ this.editMode = false;
+ this.ui.namespaceTree.show();
+ this.$(".editBox").hide();
+ this.updateToActualData();
+ this.panelOpenClose();
+ },
+ panelOpenClose: function() {
+ var collection = this.editMode ? this.collection : this.actualCollection;
+ if (collection && collection.length === 0) {
+ this.$el.find(".panel-heading").addClass("collapsed");
+ this.$el.find(".panel-collapse.collapse").removeClass("in");
+ this.ui.addNameSpace.text("Add");
+ this.ui.addNameSpace.attr("data-original-title", "Add");
+ } else {
+ this.ui.addNameSpace.text("Edit");
+ this.ui.addNameSpace.attr("data-original-title", "Edit All");
+ this.$el.find(".panel-heading").removeClass("collapsed");
+ this.$el.find(".panel-collapse.collapse").addClass("in");
+ }
+ },
+ validate: function() {
+ var validation = true;
+ this.$el.find('.custom-col-1[data-id="value"] [data-key]').each(function(el) {
+ var val = $(this).val(),
+ elIsSelect2 = $(this).hasClass("select2-hidden-accessible");
+ if (_.isString(val)) {
+ val = val.trim();
+ }
+ if (_.isEmpty(val)) {
+ if (validation) {
+ validation = false;
+ }
+ if (elIsSelect2) {
+ $(this).siblings(".select2").find(".select2-selection").attr("style", "border-color : red !important");
+ } else {
+ $(this).css("borderColor", "red");
+ }
+ } else {
+ if (elIsSelect2) {
+ $(this).siblings(".select2").find(".select2-selection").attr("style", "");
+ } else {
+ $(this).css("borderColor", "");
+ }
+ }
+ });
+ return validation;
+ },
+ onSaveNameSpace: function() {
+ var that = this;
+ if (!this.validate()) {
+ return;
+ }
+ this.entityModel.saveNamespaceEntity(this.guid, {
+ data: JSON.stringify(this.generateData()),
+ type: "POST",
+ success: function(data) {
+ Utils.notifySuccess({
+ content: "One or more namespace attributes" + Messages.getAbbreviationMsg(false, 'editSuccessMessage')
+ });
+ that.entity.namespaceAttributes = data;
+ this.editMode = false;
+ that.fetchCollection();
+ that.onCancel();
+ },
+ complete: function(model, response) {
+ //that.hideLoader();
+ }
+ });
+ },
+ generateData: function() {
+ var finalObj = {};
+ this.collection.forEach(function(model) {
+ if (!model.has("addAttrButton")) {
+ var nameSpaceName = model.get("__internal_UI_nameSpaceName"),
+ modelObj = model.toJSON();
+ _.each(modelObj, function(o, k) {
+ if (k === "isNew" && k === "__internal_UI_nameSpaceName") {
+ delete modelObj[k];
+ return;
+ }
+ if (_.isObject(o) && o.value !== undefined) {
+ modelObj[k] = o.value;
+ }
+ })
+ if (nameSpaceName !== undefined) {
+ if (finalObj[nameSpaceName]) {
+ finalObj[nameSpaceName] = _.extend(finalObj[nameSpaceName], modelObj);
+ } else {
+ finalObj[nameSpaceName] = modelObj;
+ }
+ }
+ }
+ });
+ if (_.isEmpty(finalObj)) {
+ this.actualCollection.forEach(function(model) {
+ var nameSpaceName = model.get("__internal_UI_nameSpaceName");
+ if (nameSpaceName) {
+ finalObj[nameSpaceName] = {};
+ }
+ })
+ }
+ return finalObj;
+ },
+ createNameElement: function(options) {
+ var modelObj = { isNew: true };
+ this.collection.unshift(modelObj);
+ },
+ generateTree: function() {
+ this.ui.namespaceTree.jstree({
+ plugins: ["core", "sort", "changed", "wholerow", "conditionalselect"],
+ conditionalselect: function(node) {
+ return false;
+ },
+ state: { opened: true, selected: false },
+ core: {
+ multiple: false,
+ data: this.treeData
+ }
+ })
+ },
+ onRender: function() {
+ this.panelOpenClose();
+ this.generateTree();
+ }
+ });
+});
\ No newline at end of file