Repository: atlas Updated Branches: refs/heads/master 9300924fd -> 6ed883b3d
ATLAS-2979: Added service type dropdown to filter entitydef type Signed-off-by: Sarath Subramanian <ssubraman...@hortonworks.com> Project: http://git-wip-us.apache.org/repos/asf/atlas/repo Commit: http://git-wip-us.apache.org/repos/asf/atlas/commit/6ed883b3 Tree: http://git-wip-us.apache.org/repos/asf/atlas/tree/6ed883b3 Diff: http://git-wip-us.apache.org/repos/asf/atlas/diff/6ed883b3 Branch: refs/heads/master Commit: 6ed883b3dfc74fd86b81f1bb0325a05a88e9e5b2 Parents: 9300924 Author: Abhishek Kadam <abhishek.kada...@gmail.com> Authored: Fri Dec 21 11:43:31 2018 -0800 Committer: Sarath Subramanian <ssubraman...@hortonworks.com> Committed: Fri Dec 21 11:43:31 2018 -0800 ---------------------------------------------------------------------- dashboardv2/public/css/scss/search.scss | 90 ++++++++++++++++++++ dashboardv2/public/js/utils/Overrides.js | 89 +++++++++++++++++++ .../public/js/views/search/SearchLayoutView.js | 66 ++++++++++---- 3 files changed, 227 insertions(+), 18 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/atlas/blob/6ed883b3/dashboardv2/public/css/scss/search.scss ---------------------------------------------------------------------- diff --git a/dashboardv2/public/css/scss/search.scss b/dashboardv2/public/css/scss/search.scss index 0f9cb1c..0bb8781 100644 --- a/dashboardv2/public/css/scss/search.scss +++ b/dashboardv2/public/css/scss/search.scss @@ -139,4 +139,94 @@ $color_celeste_approx: #1D1F2B; margin: 0px; } } +} + +.typeFilter { + .dropdown { + span.type-clear-btn { + position: absolute; + color: #444444; + font-size: 8px; + right: 23px; + top: 12px; + cursor: pointer; + } + } + button.dropdown-toggle { + width: 99.5%; + text-align: left; + background-color: white; + color: $color_star_dust_approx; + border: $color_star_dust_approx; + &:hover { + color: $color_star_dust_approx !important; + border: $color_star_dust_approx !important; + } + } +} + +ul.type-filter-ul { + color: black; + padding: 10px; + max-height: 415px; + overflow: auto; + width: 100%; + padding-top: 0px; + margin-bottom: 0px; + li { + padding: 2px; + } + .typeLi li { + padding: 3px; + background-color: #f7fbff; + margin: 3px; + border: 1px solid #dbd6d6; + border-radius: 4px; + &:hover { + color: $white; + background-color: $color_star_dust_approx; + cursor: pointer; + } + &.active { + background-color: #37bb9b; + color: white; + } + } + .filterLi li { + padding: 2px; + margin: 4px; + } +} + +.dark-text { + color: black; +} + +.type-filter-dropdown { + position: absolute; + top: 5px; + background-color: #323544; +} + +.filter-sticky-div { + text-align: center; + position: sticky; + position: -webkit-sticky; + top: 0px; + background-color: white; + padding-top: 8px; + & .row { + margin-right: -10px; + margin-left: -10px; + } + & input.form-control { + border: 1px #c9c9c9 solid; + } +} + +hr.hr-filter { + margin-top: 7px; + margin-bottom: 7px; + border: 0; + border-top: 1px solid #bdc3c7; } \ No newline at end of file http://git-wip-us.apache.org/repos/asf/atlas/blob/6ed883b3/dashboardv2/public/js/utils/Overrides.js ---------------------------------------------------------------------- diff --git a/dashboardv2/public/js/utils/Overrides.js b/dashboardv2/public/js/utils/Overrides.js index 44c277d..b3b591c 100644 --- a/dashboardv2/public/js/utils/Overrides.js +++ b/dashboardv2/public/js/utils/Overrides.js @@ -133,6 +133,95 @@ define(['require', 'utils/Utils', 'marionette', 'backgrid', 'asBreadcrumbs', 'jq $(this).blur(); }); + $.fn.select2.amd.define("ServiceTypeFilterDropdownAdapter", [ + "select2/utils", + "select2/dropdown", + "select2/dropdown/attachBody", + "select2/dropdown/attachContainer", + "select2/dropdown/search", + "select2/dropdown/minimumResultsForSearch", + "select2/dropdown/closeOnSelect", + ], + function(Utils, Dropdown, AttachBody, AttachContainer, Search, MinimumResultsForSearch, CloseOnSelect) { + + // Decorate Dropdown with Search functionalities + var dropdownWithSearch = Utils.Decorate(Utils.Decorate(Dropdown, CloseOnSelect), Search); + + dropdownWithSearch.prototype.render = function() { + // Copy and modify default search render method + var $rendered = Dropdown.prototype.render.call(this); + + // Add ability for a placeholder in the search box + var placeholder = this.options.get("placeholderForSearch") || ""; + var $search = $( + '<span class="select2-search select2-search--dropdown"><div class="row">' + + '<div class="col-md-10"><input class="select2-search__field" placeholder="' + placeholder + '" type="search"' + + ' tabindex="-1" autocomplete="off" autocorrect="off" autocapitalize="off"' + + ' spellcheck="false" role="textbox" /></div>' + + '<div class="col-md-2"><button type="button" style="margin-left: -20px" class="btn btn-action btn-sm filter " title="Entity Attribute Filter"><i class="fa fa-filter"></i></button></div>' + + '</div></span>' + ); + if (!this.options.options.getFilterBox) { + throw "In order to render the filter options adapter needed getFilterBox function" + } + var $Filter = $('<ul class="type-filter-ul"></ul>'); + this.$Filter = $Filter; + this.$Filter.append(this.options.options.getFilterBox()); + this.$Filter.hide(); + + this.$searchContainer = $search; + if ($Filter.find('input[type="checkbox"]:checked').length) { + $search.find('button.filter').addClass('active'); + } else { + $search.find('button.filter').removeClass('active'); + } + this.$search = $search.find('input'); + + $rendered.prepend($search); + $rendered.append($Filter); + return $rendered; + }; + var oldDropdownWithSearchBindRef = dropdownWithSearch.prototype.bind; + dropdownWithSearch.prototype.bind = function(container, $container) { + var self = this; + oldDropdownWithSearchBindRef.call(this, container, $container); + var self = this; + this.$Filter.on('click', 'li', function() { + var itemCallback = self.options.options.onFilterItemSelect; + itemCallback && itemCallback(this); + }) + + this.$searchContainer.find('button.filter').click(function() { + container.$dropdown.find('.select2-search').hide(150); + container.$dropdown.find('.select2-results').hide(150); + self.$Filter.html(self.options.options.getFilterBox()); + self.$Filter.show(); + }); + this.$Filter.on('click', 'button.filterDone', function() { + container.$dropdown.find('.select2-search').show(150); + container.$dropdown.find('.select2-results').show(150); + self.$Filter.hide(); + var filterSubmitCallback = self.options.options.onFilterSubmit; + filterSubmitCallback && filterSubmitCallback({ + filterVal: _.map(self.$Filter.find('input[type="checkbox"]:checked'), function(item) { + return $(item).data('value') + }) + }); + }); + container.$element.on('hideFilter', function() { + container.$dropdown.find('.select2-search').show(); + container.$dropdown.find('.select2-results').show(); + self.$Filter.hide(); + }); + + } + // Decorate the dropdown+search with necessary containers + var adapter = Utils.Decorate(dropdownWithSearch, AttachContainer); + adapter = Utils.Decorate(adapter, AttachBody); + + return adapter; + }); + // For placeholder support if (!('placeholder' in HTMLInputElement.prototype)) { var originalRender = Backbone.Marionette.LayoutView.prototype.render; http://git-wip-us.apache.org/repos/asf/atlas/blob/6ed883b3/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 b57bb63..78d683d 100644 --- a/dashboardv2/public/js/views/search/SearchLayoutView.js +++ b/dashboardv2/public/js/views/search/SearchLayoutView.js @@ -15,7 +15,6 @@ * See the License for the specific language governing permissions and * limitations under the License. */ - define(['require', 'backbone', 'hbs!tmpl/search/SearchLayoutView_tmpl', @@ -92,6 +91,7 @@ define(['require', _.extend(this, _.pick(options, 'value', 'typeHeaders', 'searchVent', 'entityDefCollection', 'enumDefCollection', 'classificationDefCollection', 'searchTableColumns', 'searchTableFilters', 'entityCountCollection')); this.type = "basic"; this.entityCountObj = _.first(this.entityCountCollection.toJSON()); + this.filterTypeSelected = []; var param = Utils.getUrlState.getQueryParams(); this.query = { dsl: { @@ -438,40 +438,68 @@ define(['require', this.updateQueryObject(paramObj); this.setValues(paramObj); }, - renderTypeTagList: function() { + getFilterBox: function() { + var serviceStr = '', + serviceArr = [], + that = this; + this.typeHeaders.fullCollection.each(function(model) { + var serviceType = model.toJSON().serviceType; + if (serviceType) { + serviceArr.push(serviceType); + } + }); + _.each(_.uniq(serviceArr), function(service) { + serviceStr += '<li><div class="pretty p-switch p-fill"><input type="checkbox" class="pull-left" data-value="' + (service) + '" value="" ' + (_.contains(that.filterTypeSelected, service) ? "checked" : "") + '/><div class="state p-primary"><label>' + (service.toUpperCase()) + '</label></div></div></li>'; + }); + var templt = serviceStr + '<hr class="hr-filter"/><div class="text-right"><div class="divider"></div><button class="btn btn-action btn-sm filterDone">Done</button></div>'; + return templt; + }, + renderTypeTagList: function(options) { var that = this; + var serviceTypeToBefiltered = (options && options.filterList); + var isTypeOnly = options && options.isTypeOnly; this.ui.typeLov.empty(); var typeStr = '<option></option>', tagStr = typeStr; this.typeHeaders.fullCollection.each(function(model) { var name = Utils.getName(model.toJSON(), 'name'); - if (model.get('category') == 'ENTITY') { + if (model.get('category') == 'ENTITY' && (serviceTypeToBefiltered && serviceTypeToBefiltered.length ? _.contains(serviceTypeToBefiltered, model.get('serviceType')) : true)) { var entityCount = (that.entityCountObj.entity.entityActive[name] + (that.entityCountObj.entity.entityDeleted[name] ? that.entityCountObj.entity.entityDeleted[name] : 0)); - typeStr += '<option value="'+ (name) +'" data-name="' + (name) + '">' + (name) + ' ' + (entityCount ? "(" + entityCount + ")" : '') + '</option>'; + typeStr += '<option value="' + (name) + '" data-name="' + (name) + '">' + (name) + ' ' + (entityCount ? "(" + entityCount + ")" : '') + '</option>'; } - if (model.get('category') == 'CLASSIFICATION') { + if (isTypeOnly == undefined && model.get('category') == 'CLASSIFICATION') { var tagEntityCount = that.entityCountObj.tag.tagEntities[name]; - tagStr += '<option value="'+ (name) +'" data-name="' + (name) + '">' + (name) + ' ' + (tagEntityCount ? "(" + tagEntityCount + ")" : '') + '</option>'; + tagStr += '<option value="' + (name) + '" data-name="' + (name) + '">' + (name) + ' ' + (tagEntityCount ? "(" + tagEntityCount + ")" : '') + '</option>'; } }); - //to insert extra classification list - _.each(Enums.addOnClassification, function(classificationName) { - tagStr += '<option>' + classificationName + '</option>'; - }); + if (_.isUndefined(isTypeOnly)) { + //to insert extra classification list + _.each(Enums.addOnClassification, function(classificationName) { + tagStr += '<option>' + classificationName + '</option>'; + }); + that.ui.tagLov.html(tagStr); + this.ui.tagLov.select2({ + placeholder: "Select Classification", + allowClear: true + }); + } that.ui.typeLov.html(typeStr); - that.ui.tagLov.html(tagStr); - this.ui.typeLov.select2({ + var typeLovSelect2 = this.ui.typeLov.select2({ placeholder: "Select Type", + dropdownAdapter: $.fn.select2.amd.require("ServiceTypeFilterDropdownAdapter"), allowClear: true, - templateSelection: function(data, container) { - $(data.element).attr('data-name', data.customValue); - return data.text; + getFilterBox: this.getFilterBox.bind(this), + onFilterSubmit: function(options) { + that.filterTypeSelected = options.filterVal; + that.renderTypeTagList({ "filterList": options.filterVal, isTypeOnly: true }) } }); - this.ui.tagLov.select2({ - placeholder: "Select Classification", - allowClear: true + typeLovSelect2.on("select2:close", function() { + typeLovSelect2.trigger("hideFilter"); }); + if (typeLovSelect2 && serviceTypeToBefiltered) { + typeLovSelect2.select2('open').trigger("change", { 'manual': true }); + } }, renderTermList: function() { var getTypeAheadData = function(data, params) { @@ -669,6 +697,8 @@ define(['require', } }, clearSearchData: function() { + this.filterTypeSelected = []; + this.renderTypeTagList(); this.updateQueryObject(); this.ui.typeLov.val("").trigger("change"); this.ui.tagLov.val("").trigger("change");