This is an automated email from the ASF dual-hosted git repository.
ppawar pushed a commit to branch branch-2.0
in repository https://gitbox.apache.org/repos/asf/atlas.git
The following commit(s) were added to refs/heads/branch-2.0 by this push:
new 6dd92eadc ATLAS-4735 : Ability to download search results from UI
6dd92eadc is described below
commit 6dd92eadcd7c3c4258e769f67d41071a2b05934e
Author: Farhan Khan <[email protected]>
AuthorDate: Thu Mar 30 18:32:47 2023 +0530
ATLAS-4735 : Ability to download search results from UI
Signed-off-by: Prasad Pawar <[email protected]>
---
dashboardv2/public/css/scss/downloads.scss | 109 +++++++++++++++
dashboardv2/public/css/scss/override.scss | 2 +-
dashboardv2/public/css/scss/style.scss | 3 +-
dashboardv2/public/js/collection/VDownloadList.js | 83 +++++++++++
.../public/js/models/VDownload.js | 53 +++----
dashboardv2/public/js/router/Router.js | 4 +-
.../search/SearchResultLayoutView_tmpl.html | 7 +-
.../site/DownloadSearchResultLayoutView_tmpl.html | 35 +++++
dashboardv2/public/js/templates/site/Header.html | 2 +
dashboardv2/public/js/utils/UrlLinks.js | 15 +-
dashboardv2/public/js/utils/Utils.js | 10 +-
.../public/js/views/search/SearchLayoutView.js | 9 +-
.../js/views/search/SearchResultLayoutView.js | 86 +++++++++++-
.../views/site/DownloadSearchResultLayoutView.js | 155 +++++++++++++++++++++
dashboardv2/public/js/views/site/Header.js | 24 +++-
dashboardv3/public/css/scss/downloads.scss | 108 ++++++++++++++
dashboardv3/public/css/scss/style.scss | 3 +-
dashboardv3/public/js/collection/VDownloadList.js | 83 +++++++++++
.../scss/style.scss => js/models/VDownload.js} | 53 +++----
dashboardv3/public/js/router/Router.js | 4 +-
.../search/SearchResultLayoutView_tmpl.html | 5 +
.../site/DownloadSearchResultLayoutView_tmpl.html | 35 +++++
dashboardv3/public/js/templates/site/Header.html | 2 +
dashboardv3/public/js/utils/UrlLinks.js | 14 +-
dashboardv3/public/js/utils/Utils.js | 10 +-
.../js/views/search/SearchDefaultLayoutView.js | 9 +-
.../js/views/search/SearchResultLayoutView.js | 86 +++++++++++-
.../views/site/DownloadSearchResultLayoutView.js | 155 +++++++++++++++++++++
dashboardv3/public/js/views/site/Header.js | 24 +++-
29 files changed, 1089 insertions(+), 99 deletions(-)
diff --git a/dashboardv2/public/css/scss/downloads.scss
b/dashboardv2/public/css/scss/downloads.scss
new file mode 100644
index 000000000..73be3b3cd
--- /dev/null
+++ b/dashboardv2/public/css/scss/downloads.scss
@@ -0,0 +1,109 @@
+// 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.
+
+.downloads-panel {
+ width: 25%;
+ position: fixed;
+ top: 65px;
+ right: -400px;
+ color: #686868;
+ font-size: 16px;
+ z-index: 999;
+ max-height: initial;
+ transition: all .3s ease;
+ box-shadow: 0px 3px 5px 0px #ccc;
+ border: 1px solid #37bb9b;
+ border-radius: 10px;
+ background-color: #fff;
+
+ .download-header {
+ padding: 10px;
+ display: flex;
+ align-items: center;
+ color: #686868;
+ border-bottom: 1px solid #ccc;
+ background-color: #eee;
+ border-top-left-radius: 10px;
+ border-top-right-radius: 10px;
+
+ .download-header-actions {
+ position: absolute;
+ right: 15px;
+ }
+
+ .pretty.p-switch.p-fill input:checked~.state.p-primary:before {
+ background-color: #37bb9b !important;
+ }
+
+ }
+
+ .downloadListLoader {
+ position: absolute;
+ left: 50%;
+ top: 50%;
+ transform: translateX(-50%, -50%);
+
+ i {
+ color: #37bb9b;
+ }
+ }
+
+ .download-body {
+ max-height: 600px;
+ overflow-y: auto;
+ position: relative;
+
+ #download-list-wrapper {
+ padding: 0px;
+ margin: 0px;
+
+ li {
+ padding: 12px;
+ border-bottom: 1px solid #ccc;
+ display: flex;
+ align-items: center;
+ position: relative;
+ color: #686868;
+
+ i {
+ color: #37bb9b;
+ }
+
+ a {
+ color: #686868 !important;
+ width: 100%;
+ }
+
+ .file-name {
+ padding: 0 10px 0 10px;
+ word-wrap: break-word;
+ width: 90%;
+ }
+
+ .download-state {
+ position: absolute;
+ right: 15px;
+ }
+ }
+ }
+ }
+}
+
+@media screen and (min-width: 768px) {
+ .download-content-wrapper {
+ width: 385px;
+ }
+}
\ No newline at end of file
diff --git a/dashboardv2/public/css/scss/override.scss
b/dashboardv2/public/css/scss/override.scss
index 99152587f..0c5f8bc0d 100644
--- a/dashboardv2/public/css/scss/override.scss
+++ b/dashboardv2/public/css/scss/override.scss
@@ -650,8 +650,8 @@ div.columnmanager-dropdown-container {
li.active>a {
background-color: transparent !important;
- border-bottom-color: #323544 !important;
border: 1px solid #38bb9b;
+ border-bottom: 2px solid #323544 !important;
color: #fff;
}
diff --git a/dashboardv2/public/css/scss/style.scss
b/dashboardv2/public/css/scss/style.scss
index a56c0af05..3932acf1c 100644
--- a/dashboardv2/public/css/scss/style.scss
+++ b/dashboardv2/public/css/scss/style.scss
@@ -38,4 +38,5 @@
@import "stats.scss";
@import "override.scss";
@import "trumbowyg.scss";
-@import "texteditor.scss";
\ No newline at end of file
+@import "texteditor.scss";
+@import "downloads.scss";
\ No newline at end of file
diff --git a/dashboardv2/public/js/collection/VDownloadList.js
b/dashboardv2/public/js/collection/VDownloadList.js
new file mode 100644
index 000000000..bd2f79ed0
--- /dev/null
+++ b/dashboardv2/public/js/collection/VDownloadList.js
@@ -0,0 +1,83 @@
+/**
+ * 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',
+ 'utils/Globals',
+ 'collection/BaseCollection',
+ 'models/VDownload',
+ 'utils/UrlLinks',
+ 'utils/Utils'
+], function(require, Globals, BaseCollection, VDownload, UrlLinks, Utils) {
+ 'use strict';
+ var VDownloadLists = BaseCollection.extend(
+ //Prototypal attributes
+ {
+ url: UrlLinks.downloadBasicSearchResultsCSV(),
+ model: VDownload,
+ initialize: function() {
+ this.modelName = 'VDownloads';
+ this.modelAttrName = 'generateSearchResultsCSV';
+ },
+ parseRecords: function(resp, options) {
+ try {
+ if (!this.modelAttrName) {
+ throw new Error("this.modelAttrName not defined for "
+ this);
+ }
+ if (resp[this.modelAttrName]) {
+ return resp[this.modelAttrName];
+ } else {
+ return resp
+ }
+
+ } catch (e) {
+ console.log(e);
+ }
+ },
+ getDownloadsList: function(options) {
+ var url = UrlLinks.getDownloadsList();
+
+ options = _.extend({
+ contentType: 'application/json',
+ dataType: 'json'
+ }, options);
+
+ return this.constructor.nonCrudOperation.call(this, url,
'GET', options);
+ },
+ startDownloading: function(options) {
+ var queryParams = Utils.getUrlState.getQueryParams(),
+ url = queryParams.searchType === "basic" ?
UrlLinks.downloadBasicSearchResultsCSV() :
UrlLinks.downloadAdvanceSearchResultsCSV(),
+ options = _.extend({
+ contentType: 'application/json',
+ dataType: 'json'
+ }, options);
+
+ return this.constructor.nonCrudOperation.call(this, url,
'POST', options);
+ }
+ },
+ //Static Class Members
+ {
+ /**
+ * Table Cols to be passed to Backgrid
+ * UI has to use this as base and extend this.
+ *
+ */
+ tableCols: {}
+ }
+ );
+ return VDownloadLists;
+});
\ No newline at end of file
diff --git a/dashboardv3/public/css/scss/style.scss
b/dashboardv2/public/js/models/VDownload.js
similarity index 55%
copy from dashboardv3/public/css/scss/style.scss
copy to dashboardv2/public/js/models/VDownload.js
index 53e838598..ab279dde4 100644
--- a/dashboardv3/public/css/scss/style.scss
+++ b/dashboardv2/public/js/models/VDownload.js
@@ -1,4 +1,4 @@
-/*
+/**
* 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
@@ -16,27 +16,30 @@
* limitations under the License.
*/
-@import "__mixin.scss";
-@import "__variable.scss";
-@import "common.scss";
-@import "table.scss";
-@import "tab.scss";
-@import "form.scss";
-@import "nav.scss";
-@import "panel.scss";
-@import "loader.scss";
-@import "graph.scss";
-@import "relationship.scss";
-@import "old-style.scss";
-@import "theme.scss";
-@import "tag.scss";
-@import "search.scss";
-@import "profile-table.scss";
-@import "glossary.scss";
-@import "wizard.scss";
-@import "business-metadata.scss";
-@import "stats.scss";
-@import "override.scss";
-@import "leftsidebar.scss";
-@import "trumbowyg.scss";
-@import "texteditor.scss";
\ No newline at end of file
+define(['require',
+ 'utils/Globals',
+ 'models/BaseModel',
+ 'utils/UrlLinks'
+], function(require, Globals, vBaseModel, UrlLinks) {
+ 'use strict';
+ var VDownload = vBaseModel.extend({
+ urlRoot: UrlLinks.downloadBasicSearchResultsCSV(),
+
+ defaults: {},
+
+ serverSchema: {},
+
+ idAttribute: 'id',
+
+ initialize: function() {
+ this.modelName = 'VDownload';
+ },
+ toString: function() {
+ return this.get('name');
+ },
+ /*************************
+ * Non - CRUD operations
+ *************************/
+ }, {});
+ return VDownload;
+});
\ No newline at end of file
diff --git a/dashboardv2/public/js/router/Router.js
b/dashboardv2/public/js/router/Router.js
index 84e5f98e1..9ba2e33fd 100644
--- a/dashboardv2/public/js/router/Router.js
+++ b/dashboardv2/public/js/router/Router.js
@@ -63,6 +63,7 @@ define([
this.listenTo(this, 'route', this.postRouteExecute, this);
this.searchVent = new Backbone.Wreqr.EventAggregator();
this.importVent = new Backbone.Wreqr.EventAggregator();
+ this.exportVent = new Backbone.Wreqr.EventAggregator();
this.glossaryCollection = new VGlossaryList([], {
comparator: function(item) {
return item.get("name");
@@ -82,7 +83,8 @@ define([
}
this.ventObj = {
searchVent: this.searchVent,
- importVent: this.importVent
+ importVent: this.importVent,
+ exportVent: this.exportVent
}
this.sharedObj = {
searchTableColumns: {},
diff --git
a/dashboardv2/public/js/templates/search/SearchResultLayoutView_tmpl.html
b/dashboardv2/public/js/templates/search/SearchResultLayoutView_tmpl.html
index 5c2e9ccc8..47362fb0f 100644
--- a/dashboardv2/public/js/templates/search/SearchResultLayoutView_tmpl.html
+++ b/dashboardv2/public/js/templates/search/SearchResultLayoutView_tmpl.html
@@ -38,8 +38,13 @@
</div>
<div style="padding-top: 0px;">
<div class="row form-group pagination-box filter-box"
style="display: none;">
- <div class="col-sm-12 inline-content-fr no-padding-left">
+ <div class="col-sm-12 inline-content-fr">
<div class="inline" data-id="colManager"></div>
+ {{#if isSearchTab}}
+ <button type="button" data-id="downloadSearchResult"
class="download-results btn btn-action btn-sm" title="Download Search Results">
+ <i class="fa fa-download"
aria-hidden="true"></i> Download
+ </button>
+ {{/if}}
<div class="inline">
<a href="javascript:void(0)" class="multiSelectTag
assignTag btn btn-action btn-sm" style="display:none" title="Assign
Classification" data-id="addAssignTag"><i class="fa
fa-plus"></i> Classification</a>
</div>
diff --git
a/dashboardv2/public/js/templates/site/DownloadSearchResultLayoutView_tmpl.html
b/dashboardv2/public/js/templates/site/DownloadSearchResultLayoutView_tmpl.html
new file mode 100644
index 000000000..c79bcd19e
--- /dev/null
+++
b/dashboardv2/public/js/templates/site/DownloadSearchResultLayoutView_tmpl.html
@@ -0,0 +1,35 @@
+<!--
+ * 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 id="downloads-panel" class="downloads-panel">
+ <div id="download-header" class="download-header">
+ <span data-id="downloadtitle">Downloads</span>
+ <div class="download-header-actions">
+ <div class="pretty p-switch p-fill" style="margin-right: 20px">
+ <input type="checkbox" data-id="toggleDownloads" title="" />
+ <div class="state p-primary">
+ <label></label>
+ </div>
+ </div><button data-id="refreshDownloads" class="btn btn-action
btn-sm"><i class="fa fa-refresh" aria-hidden="true"></i></button> <button
data-id="closeDownloads" class="btn btn-action btn-sm"><i class="fa fa-times"
aria-hidden="true"></i></button>
+ </div>
+ </div>
+ <div id="download-body" class="download-body">
+ <ul id="download-list-wrapper" data-id="downloadListContainer"></ul>
+ </div>
+ <div class="downloadListLoader" data-id="downloadListLoader">
+ <i class="fa fa-refresh fa-spin-custom"></i>
+ </div>
+</div>
\ No newline at end of file
diff --git a/dashboardv2/public/js/templates/site/Header.html
b/dashboardv2/public/js/templates/site/Header.html
index 572e39e78..9987f95df 100644
--- a/dashboardv2/public/js/templates/site/Header.html
+++ b/dashboardv2/public/js/templates/site/Header.html
@@ -35,6 +35,7 @@
<td>
<table class="header-menu">
<tr>
+ <td><a class="show-downloads"
href="javascript:void(0);" data-id="showDownloads" title="Downloads"><i
class="fa fa-arrow-circle-down"></i></a></td>
<td><a class="show-stat" href="javascript:void(0);"
title="Statistics"><i class="fa fa-bar-chart"></i></a></td>
<td>
<a href="javascript:void(0);"
data-toggle="dropdown" aria-haspopup="true" aria-expanded="false"
class="user-dropdown"><i class="fa fa-user user-circle "></i><span
class="userName"></span></a>
@@ -82,4 +83,5 @@
</td>
</tr>
</table>
+ <div data-id="r_DownloadSearchResult"></div>
</header>
\ No newline at end of file
diff --git a/dashboardv2/public/js/utils/UrlLinks.js
b/dashboardv2/public/js/utils/UrlLinks.js
index 8cdda1e16..c6b1af06a 100644
--- a/dashboardv2/public/js/utils/UrlLinks.js
+++ b/dashboardv2/public/js/utils/UrlLinks.js
@@ -55,7 +55,7 @@ define(['require', 'utils/Enums', 'utils/Utils',
'underscore'], function(require
metricsCollectionTimeApiUrl: function() {
return this.baseUrl + '/admin/metricsstat/'
},
- metricsGraphUrl:function(){
+ metricsGraphUrl: function() {
return this.baseUrl + '/admin/metricsstats/charts'
},
pendingTaskApiUrl: function() {
@@ -286,8 +286,19 @@ define(['require', 'utils/Enums', 'utils/Utils',
'underscore'], function(require
},
adminApiUrl: function() {
return this.baseUrl + '/admin/audits';
+ },
+ downloadBasicSearchResultsCSV: function() {
+ return this.baseUrlV2 + '/search/basic/download/create_file';
+ },
+ downloadAdvanceSearchResultsCSV: function() {
+ return this.baseUrlV2 + '/search/dsl/download/create_file';
+ },
+ getDownloadsList: function() {
+ return this.baseUrlV2 + '/search/download/status';
+ },
+ downloadSearchResultsFileUrl: function(fileName) {
+ return this.baseUrlV2 + '/search/download/' + fileName;
}
-
});
return UrlLinks;
diff --git a/dashboardv2/public/js/utils/Utils.js
b/dashboardv2/public/js/utils/Utils.js
index a83f3c17c..106fb7bd3 100644
--- a/dashboardv2/public/js/utils/Utils.js
+++ b/dashboardv2/public/js/utils/Utils.js
@@ -1313,5 +1313,13 @@ define(['require', 'utils/Globals', 'pnotify',
'utils/Messages', 'utils/Enums',
$('.nav.nav-tabs').find('[role="' + tabActive +
'"]').addClass('active').siblings().removeClass('active');
$('.tab-content').find('[role="' + tabActive +
'"]').addClass('active').siblings().removeClass('active');
}
+
+ Utils.disableRefreshButton = function(el, that) {
+ var that = that;
+ el.attr('disabled', true);
+ setTimeout(function() {
+ el.attr('disabled', false);
+ }, 1000);
+ }
return Utils;
-});
+});
\ No newline at end of file
diff --git a/dashboardv2/public/js/views/search/SearchLayoutView.js
b/dashboardv2/public/js/views/search/SearchLayoutView.js
index ec18d9937..c59a5d83e 100644
--- a/dashboardv2/public/js/views/search/SearchLayoutView.js
+++ b/dashboardv2/public/js/views/search/SearchLayoutView.js
@@ -256,13 +256,6 @@ define(['require',
this.setInitialEntityVal = false;
}
},
- disableRefreshButton: function() {
- var that = this;
- this.ui.refreshBtn.attr('disabled', true);
- setTimeout(function() {
- that.ui.refreshBtn.attr('disabled', false);
- }, 1000);
- },
makeFilterButtonActive: function(filtertypeParam) {
var filtertype = ['entityFilters', 'tagFilters'],
that = this;
@@ -424,7 +417,7 @@ define(['require',
}), param);
},
onRefreshButton: function() {
- this.disableRefreshButton();
+ Utils.disableRefreshButton(this.ui.refreshBtn, this);
var that = this,
apiCount = 2,
updateSearchList = function() {
diff --git a/dashboardv2/public/js/views/search/SearchResultLayoutView.js
b/dashboardv2/public/js/views/search/SearchResultLayoutView.js
index 5f57c2b2c..282ca55ba 100644
--- a/dashboardv2/public/js/views/search/SearchResultLayoutView.js
+++ b/dashboardv2/public/js/views/search/SearchResultLayoutView.js
@@ -29,8 +29,9 @@ define(['require',
'utils/Messages',
'utils/Enums',
'utils/UrlLinks',
- 'platform'
-], function(require, Backbone, tableDragger, SearchResultLayoutViewTmpl,
Modal, VEntity, Utils, Globals, VSearchList, VCommon, CommonViewFunction,
Messages, Enums, UrlLinks, platform) {
+ 'platform',
+ 'collection/VDownloadList'
+], function(require, Backbone, tableDragger, SearchResultLayoutViewTmpl,
Modal, VEntity, Utils, Globals, VSearchList, VCommon, CommonViewFunction,
Messages, Enums, UrlLinks, platform, VDownloadList) {
'use strict';
var SearchResultLayoutView = Backbone.Marionette.LayoutView.extend(
@@ -72,7 +73,8 @@ define(['require',
gotoPagebtn: "[data-id='gotoPagebtn']",
activePage: "[data-id='activePage']",
excludeSubtypes: ".exclude-subtypes",
- excludeSubClassifications: ".exclude-subclassifications"
+ excludeSubClassifications: ".exclude-subclassifications",
+ downloadResults: "[data-id='downloadSearchResult']"
},
templateHelpers: function() {
return {
@@ -141,6 +143,7 @@ define(['require',
events["click " + this.ui.checkDeletedEntity] =
'onCheckExcludeIncludeResult';
events["click " + this.ui.checkSubClassification] =
'onCheckExcludeIncludeResult';
events["click " + this.ui.checkSubType] =
'onCheckExcludeIncludeResult';
+ events["click " + this.ui.downloadResults] =
'onDownloadSearchResults';
return events;
},
/**
@@ -148,9 +151,10 @@ define(['require',
* @constructs
*/
initialize: function(options) {
- _.extend(this, _.pick(options, 'value', 'guid', 'initialView',
'isTypeTagNotExists', 'classificationDefCollection', 'entityDefCollection',
'typeHeaders', 'searchVent', 'enumDefCollection', 'tagCollection',
'searchTableColumns', 'isTableDropDisable', 'fromView', 'glossaryCollection',
'termName', 'businessMetadataDefCollection', 'profileDBView'));
+ _.extend(this, _.pick(options, 'value', 'guid', 'initialView',
'isTypeTagNotExists', 'classificationDefCollection', 'entityDefCollection',
'typeHeaders', 'searchVent', 'enumDefCollection', 'tagCollection',
'searchTableColumns', 'isTableDropDisable', 'fromView', 'glossaryCollection',
'termName', 'businessMetadataDefCollection', 'profileDBView', 'exportVent'));
this.entityModel = new VEntity();
this.searchCollection = new VSearchList();
+ this.downloadSearchResults = new VDownloadList();
this.limit = 25;
this.asyncFetchCounter = 0;
this.offset = 0;
@@ -158,6 +162,11 @@ define(['require',
this.multiSelectEntity = [];
this.activeEntityCountSelected = 0;
this.searchType = 'Basic Search';
+ this.tableColumnsLabelMap = {};
+ this.downloadSearchResultsParams = {
+ searchParameters: {},
+ attributeLabelMap: {}
+ };
this.columnOrder = null;
this.defaultColumns = ["selected", "name", "description",
"typeName", "owner", "tag", "term"];
if (this.value) {
@@ -241,6 +250,8 @@ define(['require',
this.ui.columnEmptyInfo.hide();
}
}
+
this.downloadSearchResultsParams.searchParameters.attributes =
excludeDefaultColumn;
+ this.validateAttributeLabelMap();
this.columnOrder =
this.getColumnOrder(this.REntityTableLayoutView.$el.find('.colSort
th.renderable'));
this.triggerUrl();
var attributes =
this.searchCollection.filterObj.attributes;
@@ -514,6 +525,11 @@ define(['require',
}
that.$('.searchResult').html(searchString);
}
+ if (dataOrCollection.approximateCount ||
dataOrCollection.length) {
+ that.ui.downloadResults.show();
+ } else {
+ that.ui.downloadResults.hide();
+ }
},
silent: true,
reset: true
@@ -564,6 +580,7 @@ define(['require',
Globals.searchApiCallRef =
this.searchCollection.fetch(apiObj);
}
}
+ this.downloadSearchResultsParams.searchParameters =
apiObj.data;
},
tableRender: function(options) {
var that = this,
@@ -648,6 +665,34 @@ define(['require',
that.checkTableFetch();
});
},
+ generateAttributeLabelMap: function() {
+ var that = this,
+ params = this.downloadSearchResultsParams;
+ if (params.searchParameters.attributes) {
+ _.map(params.searchParameters.attributes, function(attr) {
+ for (var label in that.tableColumnsLabelMap) {
+ if (attr === that.tableColumnsLabelMap[label]) {
+ params.attributeLabelMap[label] =
that.tableColumnsLabelMap[label];
+ }
+ }
+ });
+ }
+ },
+ validateAttributeLabelMap: function() {
+ var that = this,
+ params = this.downloadSearchResultsParams;
+ if (params.searchParameters.attributes.length !== 0) {
+ _.map(params.searchParameters.attributes, function(attr) {
+ for (var key in params.attributeLabelMap) {
+ if (params.attributeLabelMap[key] !== attr) {
+ delete params.attributeLabelMap[key];
+ }
+ }
+ });
+ } else {
+ params.attributeLabelMap = {};
+ }
+ },
getColumnOrder: function(arr) {
var obj = {};
for (var i = 0; i < arr.length; ++i) {
@@ -884,7 +929,8 @@ define(['require',
_.each(attrObj, function(obj, key) {
var key = obj.name,
isRenderable = _.contains(columnToShow,
key),
- isSortable =
obj.typeName.search(/(array|map)/i) == -1;
+ isSortable =
obj.typeName.search(/(array|map)/i) == -1,
+ columnLabel;
if (key == "name" || key == "description" ||
key == "owner") {
if (columnToShow) {
col[key].renderable = isRenderable;
@@ -894,8 +940,10 @@ define(['require',
if (key == "__historicalGuids" || key ==
"__classificationsText" || key == "__classificationNames" || key ==
"__propagatedClassificationNames") {
return;
}
+ columnLabel = Enums.systemAttributes[obj.name]
? Enums.systemAttributes[obj.name] : (_.escape(obj.isBusinessAttributes ?
obj.name : obj.name.capitalize()));
+ that.tableColumnsLabelMap[columnLabel] =
obj.name;
col[obj.name] = {
- label: Enums.systemAttributes[obj.name] ?
Enums.systemAttributes[obj.name] : (_.escape(obj.isBusinessAttributes ?
obj.name : obj.name.capitalize())),
+ label: columnLabel,
cell: "Html",
headerCell: Backgrid.HeaderHTMLDecodeCell,
editable: false,
@@ -1301,6 +1349,32 @@ define(['require',
this.fetchCollection();
},
+ onDownloadSearchResults: function() {
+ this.generateAttributeLabelMap();
+ Utils.disableRefreshButton(this.ui.downloadResults, this);
+ if (this.value.searchType !== "basic") {
+ this.downloadSearchResultsParams.searchParameters = {
+ "limit": this.limit,
+ "offset": this.offset,
+ "query": this.value.query || null,
+ "typeName": this.value.type || null
+ };
+ delete this.downloadSearchResultsParams.attributeLabelMap;
+ }
+ var apiObj = {
+ sort: false,
+ data: this.downloadSearchResultsParams,
+ success: function(model, response) {
+ Utils.notifySuccess({
+ content: "The current search results have been
enqueued for download. You can access the csv file by clicking the large arrow
icon at the top of the page."
+ });
+ },
+ reset: true,
+ complete: function() {},
+ error: function(error) {}
+ }
+ this.downloadSearchResults.startDownloading(apiObj);
+ },
changePageLimit: function(e, obj) {
if (!obj || (obj && !obj.skipViewChange)) {
var limit = parseInt(this.ui.showPage.val());
diff --git a/dashboardv2/public/js/views/site/DownloadSearchResultLayoutView.js
b/dashboardv2/public/js/views/site/DownloadSearchResultLayoutView.js
new file mode 100644
index 000000000..85335eef5
--- /dev/null
+++ b/dashboardv2/public/js/views/site/DownloadSearchResultLayoutView.js
@@ -0,0 +1,155 @@
+/**
+ * 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/site/DownloadSearchResultLayoutView_tmpl',
+ 'utils/Utils',
+ 'utils/UrlLinks',
+ 'utils/Globals',
+ 'collection/VDownloadList'
+], function(require, Backbone, DownloadSearchResultLayoutViewTmpl, Utils,
UrlLinks, Globals, VDownloadList) {
+ 'use strict';
+
+ var DownloadSearchResultLayoutView = Backbone.Marionette.LayoutView.extend(
+ /** @lends SearchLayoutView */
+ {
+ _viewName: 'DownloadSearchResultLayoutView',
+
+ template: DownloadSearchResultLayoutViewTmpl,
+
+ /** Layout sub regions */
+ regions: {},
+
+ /** ui selector cache */
+ ui: {
+ downloadsPanel: ".downloads-panel",
+ closeDownloadsButton: "[data-id='closeDownloads']",
+ downloadListContainer: "[data-id='downloadListContainer']",
+ downloadTitle: "[data-id='downloadtitle']",
+ refreshDownloadsButton: "[data-id='refreshDownloads']",
+ loader: "[data-id='downloadListLoader']",
+ toggleDownloads: "[data-id='toggleDownloads']"
+ },
+
+ /** ui events hash */
+ events: function() {
+ var events = {},
+ that = this;
+ events['click ' + this.ui.closeDownloadsButton] =
"onHideDownloads";
+ events['click ' + this.ui.refreshDownloadsButton] =
"onRefreshDownloads";
+ events['change ' + this.ui.toggleDownloads] = function(e) {
+ this.showCompletedDownloads = !this.showCompletedDownloads;
+ if(this.showCompletedDownloads){
+ this.ui.toggleDownloads.attr("data-original-title",
"Display All Files");
+ } else {
+ this.ui.toggleDownloads.attr("data-original-title",
"Display Available Files");
+ }
+ this.genrateDownloadList();
+ }
+ return events;
+ },
+ /**
+ * intialize a new DownloadSearchResultLayoutView Layout
+ * @constructs
+ */
+ initialize: function(options) {
+ this.options = options;
+ this.showDownloads = new VDownloadList();
+ this.showCompletedDownloads = true;
+ this.downloadsData = [];
+ this.bindEvents();
+ },
+ bindEvents: function() {
+ this.listenTo(this.options.exportVent,
"downloads:showDownloads", function() {
+ this.onShowDownloads();
+ });
+ },
+ onRender: function() {
+ this.ui.toggleDownloads.attr("data-original-title", "Display
All Files");
+ },
+ initializeValues: function() {},
+ fetchDownloadsData: function() {
+ var that = this;
+ var apiObj = {
+ success: function(data, response) {
+ that.downloadsData = data.searchDownloadRecords;
+ that.genrateDownloadList();
+ },
+ complete: function() {
+ that.hideLoader();
+ },
+ reset: true
+ }
+ this.showDownloads.getDownloadsList(apiObj);
+ },
+ genrateDownloadList: function() {
+ var that = this,
+ stateIconEl = "",
+ completedDownloads = "",
+ allDownloads = "",
+ downloadList = "",
+ sortedData = _.sortBy(this.downloadsData, function(obj){
+ return obj.createdTime;
+ }).reverse();
+ if (sortedData.length) {
+ _.each(sortedData, function(obj) {
+ if (obj.status === "PENDING") {
+ stateIconEl = "<span class='download-state'><i
class='fa fa-refresh fa-spin-custom' aria-hidden='true'></i></span>";
+ } else {
+ stateIconEl = "<span class='download-state'><a
href=" + UrlLinks.downloadSearchResultsFileUrl(obj.fileName) + "><i class='fa
fa-arrow-circle-o-down fa-lg' aria-hidden='true'></i></a></span>";
+ completedDownloads += "<li><i class='fa
fa-file-excel-o fa-lg' aria-hidden='true'></i><span class='file-name'>" +
obj.fileName + "</span>" + stateIconEl + "</li>"
+ }
+ allDownloads += "<li><i class='fa fa-file-excel-o
fa-lg' aria-hidden='true'></i><span class='file-name'>" + obj.fileName +
"</span>" + stateIconEl + "</li>";
+ });
+ } else {
+ completedDownloads = allDownloads = "<li
class='text-center' style='border-bottom:none'>No Data Found</li>"
+ }
+
+ if (this.downloadsData.length && completedDownloads === "") {
+ completedDownloads = "<li class='text-center'
style='border-bottom:none'>No Data Found</li>";
+ }
+
+ downloadList = this.showCompletedDownloads ?
completedDownloads : allDownloads;
+ this.ui.downloadListContainer.empty();
+ this.ui.downloadListContainer.html(downloadList);
+ },
+ onRefreshDownloads: function() {
+ var that = this;
+ Utils.disableRefreshButton(this.ui.refreshDownloadsButton,
this);
+ this.showLoader();
+ that.fetchDownloadsData();
+ },
+ onShowDownloads: function() {
+ this.fetchDownloadsData();
+ this.showLoader();
+ this.ui.downloadsPanel.css("right", "20px");
+ },
+ onHideDownloads: function() {
+ this.ui.downloadsPanel.css("right", "-400px")
+ },
+ showLoader: function() {
+ this.$('.downloadListLoader').show();
+ this.$('.downloadListOverlay').show();
+ },
+ hideLoader: function(options) {
+ this.$('.downloadListLoader').hide();
+ this.$('.downloadListOverlay').hide();
+ }
+ });
+ return DownloadSearchResultLayoutView;
+});
\ No newline at end of file
diff --git a/dashboardv2/public/js/views/site/Header.js
b/dashboardv2/public/js/views/site/Header.js
index ecca92952..0e84830d1 100644
--- a/dashboardv2/public/js/views/site/Header.js
+++ b/dashboardv2/public/js/views/site/Header.js
@@ -22,13 +22,16 @@ define(['require',
'utils/Globals',
'utils/Utils',
'utils/UrlLinks',
+ 'collection/VDownloadList',
'jquery-ui'
-], function(require, tmpl, CommonViewFunction, Globals, Utils, UrlLinks) {
+], function(require, tmpl, CommonViewFunction, Globals, Utils, UrlLinks,
VDownloadList) {
'use strict';
var Header = Marionette.LayoutView.extend({
template: tmpl,
- regions: {},
+ regions: {
+ RDownloadSearchResult: "[data-id='r_DownloadSearchResult']"
+ },
templateHelpers: function() {
return {
glossaryImportTempUrl: UrlLinks.glossaryImportTempUrl(),
@@ -47,7 +50,8 @@ define(['require',
showDebug: "[data-id='showDebug']",
uiSwitch: "[data-id='uiSwitch']",
glossaryImport: "[data-id='glossaryImport']",
- businessMetadataImport: "[data-id='businessMetadataImport']"
+ businessMetadataImport: "[data-id='businessMetadataImport']",
+ showDownloads: "[data-id='showDownloads']"
},
events: function() {
var events = {};
@@ -101,10 +105,13 @@ define(['require',
updateTabState: true
});
};
-
+ events['click ' + this.ui.showDownloads] = function(e) {
+ this.exportVent.trigger("downloads:showDownloads");
+ };
return events;
},
initialize: function(options) {
+ _.extend(this, _.pick(options, 'exportVent'));
this.bindEvent();
this.options = options;
},
@@ -130,6 +137,7 @@ define(['require',
that.$('.userName').html(Globals.userLogedIn.response.userName);
}
this.initializeGlobalSearch();
+ this.renderDownloadSearchResultview();
},
onShow: function() {
this.setSearchBoxWidth();
@@ -327,7 +335,13 @@ define(['require',
isGlossary: isGlossary
});
});
+ },
+ renderDownloadSearchResultview: function() {
+ var that = this;
+ require(['views/site/DownloadSearchResultLayoutView'],
function(DownloadSearchResultLayoutView) {
+ that.RDownloadSearchResult.show(new
DownloadSearchResultLayoutView(that.options));
+ });
}
});
return Header;
-});
+});
\ No newline at end of file
diff --git a/dashboardv3/public/css/scss/downloads.scss
b/dashboardv3/public/css/scss/downloads.scss
new file mode 100644
index 000000000..9c1ced6fa
--- /dev/null
+++ b/dashboardv3/public/css/scss/downloads.scss
@@ -0,0 +1,108 @@
+// 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.
+
+.downloads-panel {
+ width: 25%;
+ position: fixed;
+ top: 65px;
+ right: -400px;
+ color: #686868;
+ font-size: 16px;
+ z-index: 999;
+ max-height: initial;
+ transition: all .3s ease;
+ box-shadow: 0px 3px 5px 0px #ccc;
+ border: 1px solid #37bb9b;
+ border-radius: 10px;
+ background-color: #fff;
+
+ .download-header {
+ padding: 10px;
+ display: flex;
+ align-items: center;
+ color: #686868;
+ border-bottom: 1px solid #ccc;
+ background-color: #eee;
+ border-top-left-radius: 10px;
+ border-top-right-radius: 10px;
+
+ .download-header-actions {
+ position: absolute;
+ right: 15px;
+ }
+
+ .pretty.p-switch.p-fill input:checked~.state.p-primary:before {
+ background-color: #37bb9b !important;
+ }
+ }
+
+ .downloadListLoader {
+ position: absolute;
+ left: 50%;
+ top: 50%;
+ transform: translateX(-50%, -50%);
+
+ i {
+ color: #37bb9b;
+ }
+ }
+
+ .download-body {
+ max-height: 600px;
+ overflow-y: auto;
+ position: relative;
+
+ #download-list-wrapper {
+ padding: 0px;
+ margin: 0px;
+
+ li {
+ padding: 12px;
+ border-bottom: 1px solid #ccc;
+ display: flex;
+ align-items: center;
+ position: relative;
+ color: #686868;
+
+ i {
+ color: #37bb9b;
+ }
+
+ a {
+ color: #686868 !important;
+ width: 100%;
+ }
+
+ .file-name {
+ padding: 0 10px 0 10px;
+ word-wrap: break-word;
+ width: 90%;
+ }
+
+ .download-state {
+ position: absolute;
+ right: 15px;
+ }
+ }
+ }
+ }
+}
+
+@media screen and (min-width: 768px) {
+ .download-content-wrapper {
+ width: 385px;
+ }
+}
\ No newline at end of file
diff --git a/dashboardv3/public/css/scss/style.scss
b/dashboardv3/public/css/scss/style.scss
index 53e838598..7464bcb58 100644
--- a/dashboardv3/public/css/scss/style.scss
+++ b/dashboardv3/public/css/scss/style.scss
@@ -39,4 +39,5 @@
@import "override.scss";
@import "leftsidebar.scss";
@import "trumbowyg.scss";
-@import "texteditor.scss";
\ No newline at end of file
+@import "texteditor.scss";
+@import "downloads.scss";
\ No newline at end of file
diff --git a/dashboardv3/public/js/collection/VDownloadList.js
b/dashboardv3/public/js/collection/VDownloadList.js
new file mode 100644
index 000000000..bd2f79ed0
--- /dev/null
+++ b/dashboardv3/public/js/collection/VDownloadList.js
@@ -0,0 +1,83 @@
+/**
+ * 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',
+ 'utils/Globals',
+ 'collection/BaseCollection',
+ 'models/VDownload',
+ 'utils/UrlLinks',
+ 'utils/Utils'
+], function(require, Globals, BaseCollection, VDownload, UrlLinks, Utils) {
+ 'use strict';
+ var VDownloadLists = BaseCollection.extend(
+ //Prototypal attributes
+ {
+ url: UrlLinks.downloadBasicSearchResultsCSV(),
+ model: VDownload,
+ initialize: function() {
+ this.modelName = 'VDownloads';
+ this.modelAttrName = 'generateSearchResultsCSV';
+ },
+ parseRecords: function(resp, options) {
+ try {
+ if (!this.modelAttrName) {
+ throw new Error("this.modelAttrName not defined for "
+ this);
+ }
+ if (resp[this.modelAttrName]) {
+ return resp[this.modelAttrName];
+ } else {
+ return resp
+ }
+
+ } catch (e) {
+ console.log(e);
+ }
+ },
+ getDownloadsList: function(options) {
+ var url = UrlLinks.getDownloadsList();
+
+ options = _.extend({
+ contentType: 'application/json',
+ dataType: 'json'
+ }, options);
+
+ return this.constructor.nonCrudOperation.call(this, url,
'GET', options);
+ },
+ startDownloading: function(options) {
+ var queryParams = Utils.getUrlState.getQueryParams(),
+ url = queryParams.searchType === "basic" ?
UrlLinks.downloadBasicSearchResultsCSV() :
UrlLinks.downloadAdvanceSearchResultsCSV(),
+ options = _.extend({
+ contentType: 'application/json',
+ dataType: 'json'
+ }, options);
+
+ return this.constructor.nonCrudOperation.call(this, url,
'POST', options);
+ }
+ },
+ //Static Class Members
+ {
+ /**
+ * Table Cols to be passed to Backgrid
+ * UI has to use this as base and extend this.
+ *
+ */
+ tableCols: {}
+ }
+ );
+ return VDownloadLists;
+});
\ No newline at end of file
diff --git a/dashboardv3/public/css/scss/style.scss
b/dashboardv3/public/js/models/VDownload.js
similarity index 55%
copy from dashboardv3/public/css/scss/style.scss
copy to dashboardv3/public/js/models/VDownload.js
index 53e838598..ab279dde4 100644
--- a/dashboardv3/public/css/scss/style.scss
+++ b/dashboardv3/public/js/models/VDownload.js
@@ -1,4 +1,4 @@
-/*
+/**
* 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
@@ -16,27 +16,30 @@
* limitations under the License.
*/
-@import "__mixin.scss";
-@import "__variable.scss";
-@import "common.scss";
-@import "table.scss";
-@import "tab.scss";
-@import "form.scss";
-@import "nav.scss";
-@import "panel.scss";
-@import "loader.scss";
-@import "graph.scss";
-@import "relationship.scss";
-@import "old-style.scss";
-@import "theme.scss";
-@import "tag.scss";
-@import "search.scss";
-@import "profile-table.scss";
-@import "glossary.scss";
-@import "wizard.scss";
-@import "business-metadata.scss";
-@import "stats.scss";
-@import "override.scss";
-@import "leftsidebar.scss";
-@import "trumbowyg.scss";
-@import "texteditor.scss";
\ No newline at end of file
+define(['require',
+ 'utils/Globals',
+ 'models/BaseModel',
+ 'utils/UrlLinks'
+], function(require, Globals, vBaseModel, UrlLinks) {
+ 'use strict';
+ var VDownload = vBaseModel.extend({
+ urlRoot: UrlLinks.downloadBasicSearchResultsCSV(),
+
+ defaults: {},
+
+ serverSchema: {},
+
+ idAttribute: 'id',
+
+ initialize: function() {
+ this.modelName = 'VDownload';
+ },
+ toString: function() {
+ return this.get('name');
+ },
+ /*************************
+ * Non - CRUD operations
+ *************************/
+ }, {});
+ return VDownload;
+});
\ No newline at end of file
diff --git a/dashboardv3/public/js/router/Router.js
b/dashboardv3/public/js/router/Router.js
index 72736898c..87475fd4e 100644
--- a/dashboardv3/public/js/router/Router.js
+++ b/dashboardv3/public/js/router/Router.js
@@ -68,6 +68,7 @@ define([
this.listenTo(this, "route", this.postRouteExecute, this);
this.searchVent = new Backbone.Wreqr.EventAggregator();
this.categoryEvent = new Backbone.Wreqr.EventAggregator();
+ this.exportVent = new Backbone.Wreqr.EventAggregator();
this.glossaryCollection = new VGlossaryList([], {
comparator: function(item) {
return item.get("name");
@@ -86,7 +87,8 @@ define([
};
this.ventObj = {
searchVent: this.searchVent,
- categoryEvent: this.categoryEvent
+ categoryEvent: this.categoryEvent,
+ exportVent: this.exportVent
}
this.sharedObj = {
searchTableColumns: {},
diff --git
a/dashboardv3/public/js/templates/search/SearchResultLayoutView_tmpl.html
b/dashboardv3/public/js/templates/search/SearchResultLayoutView_tmpl.html
index d163bfa51..3493972fe 100644
--- a/dashboardv3/public/js/templates/search/SearchResultLayoutView_tmpl.html
+++ b/dashboardv3/public/js/templates/search/SearchResultLayoutView_tmpl.html
@@ -43,6 +43,11 @@
{{#if entityCreate}}
<div class="inline"><button class="btn btn-action btn-sm"
data-id="createEntity"><i class="fa fa-plus"></i> Create
Entity</button></div>
{{/if}}
+ {{#if isSearchTab}}
+ <button type="button" data-id="downloadSearchResult"
class="btn btn-action btn-sm" title="Download Search Results">
+ <i class="fa fa-download"
aria-hidden="true"></i> Download
+ </button>
+ {{/if}}
<div class="inline"><button title="Save as custom filter"
class="btn btn-action btn-sm" data-id="saveFilter"><i class="fa
fa-save"></i> Save Filter</button></div>
{{/if}}
<div class="inline">
diff --git
a/dashboardv3/public/js/templates/site/DownloadSearchResultLayoutView_tmpl.html
b/dashboardv3/public/js/templates/site/DownloadSearchResultLayoutView_tmpl.html
new file mode 100644
index 000000000..c79bcd19e
--- /dev/null
+++
b/dashboardv3/public/js/templates/site/DownloadSearchResultLayoutView_tmpl.html
@@ -0,0 +1,35 @@
+<!--
+ * 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 id="downloads-panel" class="downloads-panel">
+ <div id="download-header" class="download-header">
+ <span data-id="downloadtitle">Downloads</span>
+ <div class="download-header-actions">
+ <div class="pretty p-switch p-fill" style="margin-right: 20px">
+ <input type="checkbox" data-id="toggleDownloads" title="" />
+ <div class="state p-primary">
+ <label></label>
+ </div>
+ </div><button data-id="refreshDownloads" class="btn btn-action
btn-sm"><i class="fa fa-refresh" aria-hidden="true"></i></button> <button
data-id="closeDownloads" class="btn btn-action btn-sm"><i class="fa fa-times"
aria-hidden="true"></i></button>
+ </div>
+ </div>
+ <div id="download-body" class="download-body">
+ <ul id="download-list-wrapper" data-id="downloadListContainer"></ul>
+ </div>
+ <div class="downloadListLoader" data-id="downloadListLoader">
+ <i class="fa fa-refresh fa-spin-custom"></i>
+ </div>
+</div>
\ No newline at end of file
diff --git a/dashboardv3/public/js/templates/site/Header.html
b/dashboardv3/public/js/templates/site/Header.html
index afbbbf092..5a834c575 100644
--- a/dashboardv3/public/js/templates/site/Header.html
+++ b/dashboardv3/public/js/templates/site/Header.html
@@ -29,6 +29,7 @@
<div class="btn-group pull-right header-menu">
<table class="header-menu">
<tr>
+ <td><a class="show-downloads"
href="javascript:void(0);" data-id="showDownloads" title="Downloads"><i
class="fa fa-arrow-circle-down"></i></a></td>
<td><a class="show-stat"
href="javascript:void(0);" title="Statistics"><i class="fa
fa-bar-chart"></i></a></td>
<td class="user-dropdown"><a
href="javascript:void(0);" data-toggle="dropdown" aria-haspopup="true"
aria-expanded="false" class="user-dropdown"><i class="fa fa-user user-circle
"></i><span class="userName"></span></a>
<ul class="dropdown-menu pull-right
multi-level" role="menu" aria-labelledby="dropdownMenu">
@@ -54,5 +55,6 @@
</td>
</tr>
</table>
+ <div data-id="r_DownloadSearchResult"></div>
</header>
<div id="r_filterBrowserLayoutView"></div>
\ No newline at end of file
diff --git a/dashboardv3/public/js/utils/UrlLinks.js
b/dashboardv3/public/js/utils/UrlLinks.js
index 2531f1e74..1c05d17be 100644
--- a/dashboardv3/public/js/utils/UrlLinks.js
+++ b/dashboardv3/public/js/utils/UrlLinks.js
@@ -55,7 +55,7 @@ define(['require', 'utils/Enums', 'utils/Utils',
'underscore'], function(require
metricsCollectionTimeApiUrl: function() {
return this.baseUrl + '/admin/metricsstat/'
},
- metricsGraphUrl:function(){
+ metricsGraphUrl: function() {
return this.baseUrl + '/admin/metricsstats/charts'
},
pendingTaskApiUrl: function() {
@@ -281,6 +281,18 @@ define(['require', 'utils/Enums', 'utils/Utils',
'underscore'], function(require
},
adminApiUrl: function() {
return this.baseUrl + '/admin/audits';
+ },
+ downloadBasicSearchResultsCSV: function() {
+ return this.baseUrlV2 + '/search/basic/download/create_file';
+ },
+ downloadAdvanceSearchResultsCSV: function() {
+ return this.baseUrlV2 + '/search/dsl/download/create_file';
+ },
+ getDownloadsList: function() {
+ return this.baseUrlV2 + '/search/download/status';
+ },
+ downloadSearchResultsFileUrl: function(fileName) {
+ return this.baseUrlV2 + '/search/download/' + fileName;
}
});
diff --git a/dashboardv3/public/js/utils/Utils.js
b/dashboardv3/public/js/utils/Utils.js
index 40e5f0cfd..1de81f18d 100644
--- a/dashboardv3/public/js/utils/Utils.js
+++ b/dashboardv3/public/js/utils/Utils.js
@@ -1316,5 +1316,13 @@ define(['require', 'utils/Globals', 'pnotify',
'utils/Messages', 'utils/Enums',
}
//-----------------------------------------END---------------------//
+ Utils.disableRefreshButton = function(el, that) {
+ var that = that;
+ el.attr('disabled', true);
+ setTimeout(function() {
+ el.attr('disabled', false);
+ }, 1000);
+ }
+
return Utils;
-});
+});
\ No newline at end of file
diff --git a/dashboardv3/public/js/views/search/SearchDefaultLayoutView.js
b/dashboardv3/public/js/views/search/SearchDefaultLayoutView.js
index c8985b146..0463ea4a9 100644
--- a/dashboardv3/public/js/views/search/SearchDefaultLayoutView.js
+++ b/dashboardv3/public/js/views/search/SearchDefaultLayoutView.js
@@ -77,7 +77,7 @@ define(["require", "backbone", "utils/Globals",
"hbs!tmpl/search/SearchDefaultLa
if (Utils.getUrlState.isRelationTab()) {
this.options.searchVent.trigger('relationSearch:refresh');
}
- this.disableRefreshButton();
+ Utils.disableRefreshButton(this.ui.refreshSearchQuery,
this);
};
events["click " + this.ui.attrApply] = function(e) {
@@ -189,13 +189,6 @@ define(["require", "backbone", "utils/Globals",
"hbs!tmpl/search/SearchDefaultLa
}
}
},
- disableRefreshButton: function() {
- var that = this;
- this.ui.refreshSearchQuery.attr('disabled', true);
- setTimeout(function() {
- that.ui.refreshSearchQuery.attr('disabled', false);
- }, 1000);
- },
onCheckExcludeIncludeResult: function(e) {
var flag = false,
diff --git a/dashboardv3/public/js/views/search/SearchResultLayoutView.js
b/dashboardv3/public/js/views/search/SearchResultLayoutView.js
index 3b492e5eb..5189f08d8 100644
--- a/dashboardv3/public/js/views/search/SearchResultLayoutView.js
+++ b/dashboardv3/public/js/views/search/SearchResultLayoutView.js
@@ -31,8 +31,9 @@ define(['require',
'utils/Enums',
'utils/UrlLinks',
'moment',
- 'platform'
-], function(require, Backbone, tableDragger, SearchResultLayoutViewTmpl,
Modal, VEntity, Utils, Globals, VSearchList, VCommon, CommonViewFunction,
Messages, Enums, UrlLinks, moment, platform) {
+ 'platform',
+ 'collection/VDownloadList'
+], function(require, Backbone, tableDragger, SearchResultLayoutViewTmpl,
Modal, VEntity, Utils, Globals, VSearchList, VCommon, CommonViewFunction,
Messages, Enums, UrlLinks, moment, platform, VDownloadList) {
'use strict';
var SearchResultLayoutView = Backbone.Marionette.LayoutView.extend(
@@ -73,7 +74,8 @@ define(['require',
activePage: "[data-id='activePage']",
saveFilter: "[data-id='saveFilter']",
excludeSubtypes: ".exclude-subtypes",
- excludeSubClassifications: ".exclude-subclassifications"
+ excludeSubClassifications: ".exclude-subclassifications",
+ downloadResults: "[data-id='downloadSearchResult']"
},
templateHelpers: function() {
return {
@@ -148,6 +150,7 @@ define(['require',
this.searchVent.trigger("Save:Filter");
}
};
+ events["click " + this.ui.downloadResults] =
'onDownloadSearchResults'
return events;
},
/**
@@ -155,9 +158,10 @@ define(['require',
* @constructs
*/
initialize: function(options) {
- _.extend(this, _.pick(options, 'value', 'guid', 'initialView',
'isTypeTagNotExists', 'classificationDefCollection', 'entityDefCollection',
'typeHeaders', 'searchVent', 'categoryEvent', 'enumDefCollection',
'tagCollection', 'searchTableColumns', 'isTableDropDisable', 'fromView',
'glossaryCollection', 'termName', 'businessMetadataDefCollection',
'profileDBView'));
+ _.extend(this, _.pick(options, 'value', 'guid', 'initialView',
'isTypeTagNotExists', 'classificationDefCollection', 'entityDefCollection',
'typeHeaders', 'searchVent', 'categoryEvent', 'enumDefCollection',
'tagCollection', 'searchTableColumns', 'isTableDropDisable', 'fromView',
'glossaryCollection', 'termName', 'businessMetadataDefCollection',
'profileDBView', 'exportVent'));
this.entityModel = new VEntity();
this.searchCollection = new VSearchList();
+ this.downloadSearchResults = new VDownloadList();
this.limit = 25;
this.asyncFetchCounter = 0;
this.offset = 0;
@@ -165,6 +169,11 @@ define(['require',
this.multiSelectEntity = [];
this.activeEntityCountSelected = 0;
this.searchType = 'Basic Search';
+ this.tableColumnsLabelMap = {};
+ this.downloadSearchResultsParams = {
+ searchParameters: {},
+ attributeLabelMap: {}
+ };
this.columnOrder = null;
this.defaultColumns = ["selected", "name", "description",
"typeName", "owner", "tag", "term"];
if (this.value) {
@@ -248,6 +257,8 @@ define(['require',
this.ui.columnEmptyInfo.hide();
}
}
+
this.downloadSearchResultsParams.searchParameters.attributes =
excludeDefaultColumn;
+ this.validateAttributeLabelMap();
this.columnOrder =
this.getColumnOrder(this.REntityTableLayoutView.$el.find('.colSort
th.renderable'));
this.triggerUrl();
var attributes =
this.searchCollection.filterObj.attributes;
@@ -529,6 +540,11 @@ define(['require',
}
that.$('.searchResult').html(searchString);
}
+ if (dataOrCollection.approximateCount ||
dataOrCollection.length) {
+ that.ui.downloadResults.show();
+ } else {
+ that.ui.downloadResults.hide();
+ }
},
silent: true,
reset: true
@@ -579,6 +595,7 @@ define(['require',
Globals.searchApiCallRef =
this.searchCollection.fetch(apiObj);
}
}
+ this.downloadSearchResultsParams.searchParameters =
apiObj.data;
},
tableRender: function(options) {
var that = this,
@@ -660,6 +677,34 @@ define(['require',
that.checkTableFetch();
});
},
+ generateAttributeLabelMap: function() {
+ var that = this,
+ params = this.downloadSearchResultsParams;
+ if (params.searchParameters.attributes) {
+ _.map(params.searchParameters.attributes, function(attr) {
+ for (var label in that.tableColumnsLabelMap) {
+ if (attr === that.tableColumnsLabelMap[label]) {
+ params.attributeLabelMap[label] =
that.tableColumnsLabelMap[label];
+ }
+ }
+ });
+ }
+ },
+ validateAttributeLabelMap: function() {
+ var that = this,
+ params = this.downloadSearchResultsParams;
+ if (params.searchParameters.attributes.length !== 0) {
+ _.map(params.searchParameters.attributes, function(attr) {
+ for (var key in params.attributeLabelMap) {
+ if (params.attributeLabelMap[key] !== attr) {
+ delete params.attributeLabelMap[key];
+ }
+ }
+ });
+ } else {
+ params.attributeLabelMap = {};
+ }
+ },
getColumnOrder: function(arr) {
var obj = {};
for (var i = 0; i < arr.length; ++i) {
@@ -895,7 +940,8 @@ define(['require',
_.each(attrObj, function(obj, key) {
var key = obj.name,
isRenderable = _.contains(columnToShow,
key),
- isSortable =
obj.typeName.search(/(array|map)/i) == -1;
+ isSortable =
obj.typeName.search(/(array|map)/i) == -1,
+ columnLabel;
if (key == "name" || key == "description" ||
key == "owner") {
if (columnToShow) {
col[key].renderable = isRenderable;
@@ -905,8 +951,10 @@ define(['require',
if (key == "__historicalGuids" || key ==
"__classificationsText" || key == "__classificationNames" || key ==
"__propagatedClassificationNames") {
return;
}
+ columnLabel = Enums.systemAttributes[obj.name]
? Enums.systemAttributes[obj.name] : (_.escape(obj.isBusinessAttributes ?
obj.name : obj.name.capitalize()));
+ that.tableColumnsLabelMap[columnLabel] =
obj.name;
col[obj.name] = {
- label: Enums.systemAttributes[obj.name] ?
Enums.systemAttributes[obj.name] : (_.escape(obj.isBusinessAttributes ?
obj.name : obj.name.capitalize())),
+ label: columnLabel,
cell: "Html",
headerCell: Backgrid.HeaderHTMLDecodeCell,
editable: false,
@@ -1318,6 +1366,32 @@ define(['require',
this.fetchCollection();
},
+ onDownloadSearchResults: function() {
+ this.generateAttributeLabelMap();
+ Utils.disableRefreshButton(this.ui.downloadResults, this);
+ if (this.value.searchType !== "basic") {
+ this.downloadSearchResultsParams.searchParameters = {
+ "limit": this.limit,
+ "offset": this.offset,
+ "query": this.value.query || null,
+ "typeName": this.value.type || null
+ };
+ delete this.downloadSearchResultsParams.attributeLabelMap;
+ }
+ var apiObj = {
+ sort: false,
+ data: this.downloadSearchResultsParams,
+ success: function(model, response) {
+ Utils.notifySuccess({
+ content: "The current search results have been
enqueued for download. You can access the csv file by clicking the large arrow
icon at the top of the page."
+ });
+ },
+ reset: true,
+ complete: function() {},
+ error: function(error) {}
+ }
+ this.downloadSearchResults.startDownloading(apiObj);
+ },
changePageLimit: function(e, obj) {
if (!obj || (obj && !obj.skipViewChange)) {
var limit = parseInt(this.ui.showPage.val());
diff --git a/dashboardv3/public/js/views/site/DownloadSearchResultLayoutView.js
b/dashboardv3/public/js/views/site/DownloadSearchResultLayoutView.js
new file mode 100644
index 000000000..85335eef5
--- /dev/null
+++ b/dashboardv3/public/js/views/site/DownloadSearchResultLayoutView.js
@@ -0,0 +1,155 @@
+/**
+ * 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/site/DownloadSearchResultLayoutView_tmpl',
+ 'utils/Utils',
+ 'utils/UrlLinks',
+ 'utils/Globals',
+ 'collection/VDownloadList'
+], function(require, Backbone, DownloadSearchResultLayoutViewTmpl, Utils,
UrlLinks, Globals, VDownloadList) {
+ 'use strict';
+
+ var DownloadSearchResultLayoutView = Backbone.Marionette.LayoutView.extend(
+ /** @lends SearchLayoutView */
+ {
+ _viewName: 'DownloadSearchResultLayoutView',
+
+ template: DownloadSearchResultLayoutViewTmpl,
+
+ /** Layout sub regions */
+ regions: {},
+
+ /** ui selector cache */
+ ui: {
+ downloadsPanel: ".downloads-panel",
+ closeDownloadsButton: "[data-id='closeDownloads']",
+ downloadListContainer: "[data-id='downloadListContainer']",
+ downloadTitle: "[data-id='downloadtitle']",
+ refreshDownloadsButton: "[data-id='refreshDownloads']",
+ loader: "[data-id='downloadListLoader']",
+ toggleDownloads: "[data-id='toggleDownloads']"
+ },
+
+ /** ui events hash */
+ events: function() {
+ var events = {},
+ that = this;
+ events['click ' + this.ui.closeDownloadsButton] =
"onHideDownloads";
+ events['click ' + this.ui.refreshDownloadsButton] =
"onRefreshDownloads";
+ events['change ' + this.ui.toggleDownloads] = function(e) {
+ this.showCompletedDownloads = !this.showCompletedDownloads;
+ if(this.showCompletedDownloads){
+ this.ui.toggleDownloads.attr("data-original-title",
"Display All Files");
+ } else {
+ this.ui.toggleDownloads.attr("data-original-title",
"Display Available Files");
+ }
+ this.genrateDownloadList();
+ }
+ return events;
+ },
+ /**
+ * intialize a new DownloadSearchResultLayoutView Layout
+ * @constructs
+ */
+ initialize: function(options) {
+ this.options = options;
+ this.showDownloads = new VDownloadList();
+ this.showCompletedDownloads = true;
+ this.downloadsData = [];
+ this.bindEvents();
+ },
+ bindEvents: function() {
+ this.listenTo(this.options.exportVent,
"downloads:showDownloads", function() {
+ this.onShowDownloads();
+ });
+ },
+ onRender: function() {
+ this.ui.toggleDownloads.attr("data-original-title", "Display
All Files");
+ },
+ initializeValues: function() {},
+ fetchDownloadsData: function() {
+ var that = this;
+ var apiObj = {
+ success: function(data, response) {
+ that.downloadsData = data.searchDownloadRecords;
+ that.genrateDownloadList();
+ },
+ complete: function() {
+ that.hideLoader();
+ },
+ reset: true
+ }
+ this.showDownloads.getDownloadsList(apiObj);
+ },
+ genrateDownloadList: function() {
+ var that = this,
+ stateIconEl = "",
+ completedDownloads = "",
+ allDownloads = "",
+ downloadList = "",
+ sortedData = _.sortBy(this.downloadsData, function(obj){
+ return obj.createdTime;
+ }).reverse();
+ if (sortedData.length) {
+ _.each(sortedData, function(obj) {
+ if (obj.status === "PENDING") {
+ stateIconEl = "<span class='download-state'><i
class='fa fa-refresh fa-spin-custom' aria-hidden='true'></i></span>";
+ } else {
+ stateIconEl = "<span class='download-state'><a
href=" + UrlLinks.downloadSearchResultsFileUrl(obj.fileName) + "><i class='fa
fa-arrow-circle-o-down fa-lg' aria-hidden='true'></i></a></span>";
+ completedDownloads += "<li><i class='fa
fa-file-excel-o fa-lg' aria-hidden='true'></i><span class='file-name'>" +
obj.fileName + "</span>" + stateIconEl + "</li>"
+ }
+ allDownloads += "<li><i class='fa fa-file-excel-o
fa-lg' aria-hidden='true'></i><span class='file-name'>" + obj.fileName +
"</span>" + stateIconEl + "</li>";
+ });
+ } else {
+ completedDownloads = allDownloads = "<li
class='text-center' style='border-bottom:none'>No Data Found</li>"
+ }
+
+ if (this.downloadsData.length && completedDownloads === "") {
+ completedDownloads = "<li class='text-center'
style='border-bottom:none'>No Data Found</li>";
+ }
+
+ downloadList = this.showCompletedDownloads ?
completedDownloads : allDownloads;
+ this.ui.downloadListContainer.empty();
+ this.ui.downloadListContainer.html(downloadList);
+ },
+ onRefreshDownloads: function() {
+ var that = this;
+ Utils.disableRefreshButton(this.ui.refreshDownloadsButton,
this);
+ this.showLoader();
+ that.fetchDownloadsData();
+ },
+ onShowDownloads: function() {
+ this.fetchDownloadsData();
+ this.showLoader();
+ this.ui.downloadsPanel.css("right", "20px");
+ },
+ onHideDownloads: function() {
+ this.ui.downloadsPanel.css("right", "-400px")
+ },
+ showLoader: function() {
+ this.$('.downloadListLoader').show();
+ this.$('.downloadListOverlay').show();
+ },
+ hideLoader: function(options) {
+ this.$('.downloadListLoader').hide();
+ this.$('.downloadListOverlay').hide();
+ }
+ });
+ return DownloadSearchResultLayoutView;
+});
\ No newline at end of file
diff --git a/dashboardv3/public/js/views/site/Header.js
b/dashboardv3/public/js/views/site/Header.js
index e2ecd7e72..685ca69b4 100644
--- a/dashboardv3/public/js/views/site/Header.js
+++ b/dashboardv3/public/js/views/site/Header.js
@@ -21,15 +21,17 @@ define(['require',
'utils/CommonViewFunction',
'utils/Globals',
'utils/Utils',
- 'utils/UrlLinks'
-], function(require, tmpl, CommonViewFunction, Globals, Utils, UrlLinks) {
+ 'utils/UrlLinks',
+ 'collection/VDownloadList',
+], function(require, tmpl, CommonViewFunction, Globals, Utils, UrlLinks,
VDownloadList) {
'use strict';
var Header = Marionette.LayoutView.extend({
template: tmpl,
regions: {
RGlobalSearchLayoutView: "#r_globalSearchLayoutView",
- RFilterBrowserLayoutView: "#r_filterBrowserLayoutView"
+ RFilterBrowserLayoutView: "#r_filterBrowserLayoutView",
+ RDownloadSearchResult: "[data-id='r_DownloadSearchResult']"
},
templateHelpers: function() {
return {
@@ -43,7 +45,8 @@ define(['require',
administrator: "[data-id='administrator']",
showDebug: "[data-id='showDebug']",
signOut: "[data-id='signOut']",
- uiSwitch: "[data-id='uiSwitch']"
+ uiSwitch: "[data-id='uiSwitch']",
+ showDownloads: "[data-id='showDownloads']"
},
events: function() {
var events = {};
@@ -69,6 +72,9 @@ define(['require',
updateTabState: true
});
};
+ events['click ' + this.ui.showDownloads] = function(e) {
+ this.exportVent.trigger("downloads:showDownloads");
+ };
events['click ' + this.ui.showDebug] = function() {
Utils.setUrl({
url: "#!/debugMetrics",
@@ -90,6 +96,7 @@ define(['require',
},
initialize: function(options) {
+ _.extend(this, _.pick(options, 'exportVent'));
this.bindEvent();
this.options = options;
},
@@ -121,6 +128,7 @@ define(['require',
if (this.options.fromDefaultSearch !== true) {
this.renderGlobalSearch();
}
+ this.renderDownloadSearchResultview();
},
onShow: function() {
this.setSearchBoxWidth();
@@ -152,6 +160,12 @@ define(['require',
that.RFilterBrowserLayoutView.show(new
SearchFilterBrowseLayoutView(_.extend({ toggleLayoutClass:
that.toggleLayoutClass }, that.options)));
});
},
+ renderDownloadSearchResultview: function() {
+ var that = this;
+ require(['views/site/DownloadSearchResultLayoutView'],
function(DownloadSearchResultLayoutView) {
+ that.RDownloadSearchResult.show(new
DownloadSearchResultLayoutView(that.options));
+ });
+ }
});
return Header;
-});
+});
\ No newline at end of file