Skip to content
This repository has been archived by the owner on Oct 8, 2019. It is now read-only.

Commit

Permalink
Merge pull request #553 from blockchain/export-history
Browse files Browse the repository at this point in the history
Export history fixes
  • Loading branch information
Sjors authored Aug 3, 2016
2 parents be0b3e5 + 784ad6b commit ba26e04
Show file tree
Hide file tree
Showing 10 changed files with 95 additions and 83 deletions.
1 change: 0 additions & 1 deletion app/partials/common.jade
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
.left-nav(ui-view="left", ng-class="{toggled: menu.isCollapsed}")
.top-view(ui-view="top")
.main-container(ui-view="right", scroll-to-top, in-view-container, ng-click="hideMenu()")
downloader
28 changes: 12 additions & 16 deletions app/partials/export-history.jade
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,10 @@ form(role="form" name="exportForm" ng-submit="submit()" autocomplete="off" noval
helper-button(content="EXPORT_HISTORY_EXPLAIN")

.modal-body
.ph-form
.flex-row.pal
.flex-1
.flex-4.form-group(ng-show="activeCount > 1")
.ph-form.flex-row
.flex-1
.flex-4
.form-group.pal(ng-show="activeCount > 1")
ui-select.send-from-dropdown(
name="active"
ng-model="$parent.active"
Expand All @@ -18,10 +18,7 @@ form(role="form" name="exportForm" ng-submit="submit()" autocomplete="off" noval
label-origin(origin="$select.selected")
ui-select-choices(repeat="t in targets | filter:{label:$select.search} | limitTo:limit")
label-origin(origin="::t" in-view="$last && isLast(t) && incLimit()" highlight="$select.search")
.flex-1

.flex-row
.flex-3.flex-column.flex-center.flex-around.pam(ng-class="{'has-error':exportForm.$invalid || start.date > end.date}")
.flex-row.flex-center.flex-between.pal(ng-class="{'has-error':exportForm.$invalid || start.date > end.date}")
p.input-group.flex-center
input.form-control(
type="text"
Expand All @@ -33,7 +30,7 @@ form(role="form" name="exportForm" ng-submit="submit()" autocomplete="off" noval
placeholder="{{'START_DATE'|translate}}"
required)
span.ti-calendar.pointer(ng-click="start.open=true")
i.ti-arrow-down.blue
i.ti-arrow-right.blue
p.input-group.flex-center
input.form-control(
type="text"
Expand All @@ -45,14 +42,8 @@ form(role="form" name="exportForm" ng-submit="submit()" autocomplete="off" noval
placeholder="{{'END_DATE'|translate}}"
required)
span.ti-calendar.pointer(ng-click="end.open=true")
.flex-1

span.line-split.flex-center.mrl.mll

.flex-3.flex-row.flex-center.flex-around.pam
label.mll.btn.button-default(ng-model="exportFormat" uib-btn-radio="'csv'") CSV
span.upper(translate="OR")
label.mrl.btn.button-default(ng-model="exportFormat" uib-btn-radio="'xls'") XLS

.modal-footer
button.button-muted.mrm(
type="button"
Expand All @@ -63,4 +54,9 @@ form(role="form" name="exportForm" ng-submit="submit()" autocomplete="off" noval
ui-ladda="busy"
ladda-translate="EXPORT"
data-style="expand-left"
ng-show="history == null || canTriggerDownload"
ng-disabled="exportForm.$invalid || start.date > end.date")
download-button.btn.button-success(
ng-hide="history == null || canTriggerDownload"
filename="history.csv"
content="history")
11 changes: 9 additions & 2 deletions assets/js/controllers/exportHistory.controller.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,9 @@ function ExportHistoryController ($scope, $sce, $translate, $filter, format, Wal
$scope.limit = 50;
$scope.incLimit = () => $scope.limit += 50;

$scope.ableBrowsers = ['chrome', 'firefox'];
$scope.canTriggerDownload = $scope.ableBrowsers.indexOf(browserDetection().browser) > -1;

let accounts = Wallet.accounts().filter(a => !a.archived && a.index != null);
let addresses = Wallet.legacyAddresses().filter(a => !a.archived).map(a => a.address);

Expand Down Expand Up @@ -37,7 +40,6 @@ function ExportHistoryController ($scope, $sce, $translate, $filter, format, Wal
$scope.format = 'dd/MM/yyyy';
$scope.options = { minDate: new Date(1231024500000), maxDate: new Date() };

$scope.exportFormat = 'csv';
$scope.start = { open: false, date: Date.now() - 604800000 };
$scope.end = { open: false, date: Date.now() };

Expand All @@ -48,6 +50,11 @@ function ExportHistoryController ($scope, $sce, $translate, $filter, format, Wal
let start = $scope.formatDate($scope.start.date);
let end = $scope.formatDate($scope.end.date);
let active = $scope.active.address || $scope.active.xpub;
Wallet.exportHistory(start, end, active).finally(() => $scope.busy = false);
Wallet.exportHistory(start, end, active)
.then((data) => {
$scope.history = data;
$scope.canTriggerDownload && $scope.$broadcast('download');
})
.finally(() => $scope.busy = false);
};
}
28 changes: 28 additions & 0 deletions assets/js/directives/download-button.directive.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
angular
.module('walletApp')
.directive('downloadButton', downloadButton);

function downloadButton ($window, $timeout) {
const directive = {
restrict: 'E',
replace: true,
scope: {
filename: '@',
content: '='
},
template: '<a href="{{dataRef}}" download="{{filename}}" target="_blank">{{::"DOWNLOAD"|translate}}</a>',
link: link
};
return directive;

function link (scope, attr, elem) {
scope.$watch('content', (content) => {
let blob = new $window.Blob([content], {type: 'text/csv'});
scope.dataRef = $window.URL.createObjectURL(blob);
});
scope.$on('download', (event) => {
if (!scope.dataRef) return;
$timeout(() => elem.$$element[0].click());
});
}
}
23 changes: 0 additions & 23 deletions assets/js/directives/downloader.directive.js

This file was deleted.

6 changes: 3 additions & 3 deletions assets/js/services/wallet.service.js
Original file line number Diff line number Diff line change
Expand Up @@ -1131,15 +1131,15 @@ function Wallet ($http, $window, $timeout, $location, Alerts, MyWallet, MyBlockc
return $q.resolve(p)
.then(history => {
if (!history.length) return $q.reject('NO_HISTORY');
let contents = json2csv(history.map(addTxNote));
$rootScope.$broadcast('download', { contents, filename: 'history.csv' });
return json2csv(history.map(addTxNote));
})
.catch(e => {
let error = e.message || e;
if (error && error.indexOf('Too many transactions') > -1) {
if (typeof error === 'string' && error.indexOf('Too many transactions') > -1) {
error = 'TOO_MANY_TXS';
}
Alerts.displayError(error || 'UNKNOWN_ERROR');
return $q.reject(error);
});
};

Expand Down
1 change: 1 addition & 0 deletions locales/en-human.json
Original file line number Diff line number Diff line change
Expand Up @@ -270,6 +270,7 @@
"EXPORTING_FOR" : "Exporting transactions for: {{ name }}",
"NO_HISTORY" : "No transactions found in that range",
"TOO_MANY_TXS" : "Too many transactions to export, maximum of 10,000 allowed",
"DOWNLOAD": "Download File",
"SPENDABLE_ADDRESSES" : "Spendable Addresses",
"NEXT_ADDRESSES_FOR_ACCOUNT" : "Unused Addresses in {{account}}",
"PAST_ADDRESSES_FOR_ACCOUNT" : "Used Addresses in {{account}}",
Expand Down
39 changes: 39 additions & 0 deletions tests/directives/download-button_spec.coffee
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
describe "downloadButton", ->
scope = undefined
element = undefined
isoScope = undefined
$timeout = undefined

beforeEach module("walletApp")

beforeEach inject(($compile, $rootScope, $window, _$timeout_) ->
$timeout = _$timeout_

spyOn($window, 'Blob').and.callFake((data) -> toString: -> "data[#{data.join()}]")
spyOn($window.URL, 'createObjectURL').and.callFake((obj) -> "blob://#{obj}")

scope = $rootScope.$new()
scope.content = 'asdf'
scope.$digest()

element = $compile("<download-button content='content' filename='test.txt'></download-button>")(scope)
isoScope = element.isolateScope()
isoScope.$digest()
)

it "should create a data ref for content", ->
expect(isoScope.dataRef).toEqual('blob://data[asdf]')

it "should create a data ref when content is updated", ->
isoScope.content = 'abc'
isoScope.$digest()
expect(isoScope.dataRef).toEqual('blob://data[abc]')

it "should use the correct filename", ->
expect(isoScope.filename).toEqual('test.txt')

it "should click the anchor tag to trigger download", ->
spyOn(element[0], 'click')
scope.$broadcast("download")
$timeout.flush()
expect(element[0].click).toHaveBeenCalled()
33 changes: 0 additions & 33 deletions tests/directives/downloader_spec.coffee

This file was deleted.

8 changes: 3 additions & 5 deletions tests/services/wallet_service_spec.coffee
Original file line number Diff line number Diff line change
Expand Up @@ -529,10 +529,8 @@ describe "walletServices", () ->
it "should convert to csv with notes and broadcast broadcast download event", (done) ->
spyOn(Wallet, 'getNote').and.callFake((hash) -> hash == 'asdf' && 'test_note')
spyOn($rootScope, '$broadcast')
Wallet.exportHistory().then ->
expect($rootScope.$broadcast).toHaveBeenCalledWith 'download',
contents: 'sent,receive,tx,note\n1,0,asdf,test_note\n0,2,qwer,'
filename: 'history.csv'
Wallet.exportHistory().then (data) ->
expect(data).toEqual('sent,receive,tx,note\n1,0,asdf,test_note\n0,2,qwer,')
done()
$rootScope.$digest()

Expand All @@ -541,7 +539,7 @@ describe "walletServices", () ->
spyOn(MyBlockchainApi, 'exportHistory').and.returnValue([])

it "should show an error", (done) ->
Wallet.exportHistory().then ->
Wallet.exportHistory().finally ->
expect(Alerts.displayError).toHaveBeenCalledWith('NO_HISTORY')
done()
$rootScope.$digest()

0 comments on commit ba26e04

Please sign in to comment.