mirror of
https://github.com/mupen64plus-ae/acralyzer.git
synced 2024-12-03 11:11:28 +00:00
First draft of a working in-browser bugs pagination.
This commit is contained in:
parent
ee15ec2199
commit
84d82a268e
@ -51,7 +51,8 @@
|
||||
</ul>
|
||||
</li>
|
||||
<li ng-class="{active: $route.current.activetab == 'dashboard'}"><a href="#/dashboard/{{acralyzer.app}}">Dashboard</a></li>
|
||||
<li ng-class="{active: $route.current.activetab == 'reports-browser'}"><a href="#/reports-browser/{{acralyzer.app}}">Reports browser</a></li>
|
||||
<li ng-class="{active: $route.current.activetab == 'reports-browser'}"><a href="#/reports-browser/{{acralyzer.app}}">Reports</a></li>
|
||||
<li ng-class="{active: $route.current.activetab == 'bugs-browser'}"><a href="#/bugs-browser/{{acralyzer.app}}">Bugs</a></li>
|
||||
<li ng-class="{active: $route.current.activetab == 'admin'}"><a href="#/admin/{{acralyzer.app}}">Admin</a></li>
|
||||
</ul>
|
||||
|
||||
@ -131,6 +132,7 @@
|
||||
<script src="script/NavigationController.js"></script>
|
||||
<script src="script/ReportDetailsController.js"></script>
|
||||
<script src="script/ReportsBrowserControllers.js"></script>
|
||||
<script src="script/BugsBrowserControllers.js"></script>
|
||||
<script src="script/AdminControllers.js"></script>
|
||||
|
||||
<script src="script/services.js"></script>
|
||||
|
@ -3,7 +3,7 @@
|
||||
<div id="filters" class="row-fluid">
|
||||
<form ng-submit="getData()" class="form-inline">
|
||||
<div class="input-append">
|
||||
<input ng-model="reportsCount" type="number" alt="Number of reports per page" class="input-mini"/>
|
||||
<input ng-model="bugsCount" type="number" alt="Number of reports per page" class="input-mini"/>
|
||||
<button class="btn" type="submit">OK</button>
|
||||
</div>
|
||||
<select ng-model="filterName" ng-change="changeFilterValues()" ng-options="f.label for f in availableFilters">
|
||||
@ -16,38 +16,40 @@
|
||||
</label>
|
||||
</form>
|
||||
</div>
|
||||
<div id="reports-list" class="row-fluid tab-content">
|
||||
<span ng-bind-template="reports {{startNumber}} to {{endNumber}} (out of {{totalReports}}):">Loading...</span>
|
||||
<div class="row-fluid tab-content">
|
||||
<span ng-bind-template="Bugs {{startNumber}} to {{endNumber}} (out of {{totalBugs}}):">Loading...</span>
|
||||
<button class="btn btn-small" ng-click="hideSolvedBugs = !hideSolvedBugs">
|
||||
<span ng-hide="hideSolvedBugs">Hide solved bugs</span>
|
||||
<span ng-show="hideSolvedBugs">Show solved bugs</span>
|
||||
</button>
|
||||
<div class="loader" ng-show="loading"><img src="img/loader.gif"/></div>
|
||||
<div class="div-table" ng-hide="loading">
|
||||
<div ng-hide="loading" id="bugs-list" class="div-table table table-condensed">
|
||||
<div class="div-table-row">
|
||||
<div class="div-table-cell"/>
|
||||
<div class="div-table-cell"></div>
|
||||
<div class="div-table-cell"><i class="icon-time"></i></div>
|
||||
<div class="div-table-cell"><i class="icon-th-list"></i></div>
|
||||
<div class="div-table-cell"><i class="icon-gift"></i></div>
|
||||
<div class="div-table-cell"><i class="icon-bugdroid"></i></div>
|
||||
<div class="div-table-cell"><i class="icon-phone"></i></div>
|
||||
<div class="div-table-cell exceptions"><i class="icon-fire"></i></div>
|
||||
</div>
|
||||
<div class="div-table-row" ng-repeat="report in reports | filter:search" ng-class-odd="'odd'" ng-class-even="'even'" ng-cloak>
|
||||
<div class="div-table-cell actions">
|
||||
<a ng-click="loadReport(report)" class="action">
|
||||
<i class="icon-search" ng-hide="report.id == selectedReport._id" title="Display details"></i>
|
||||
<i class="icon-asterisk" ng-show="report.id == selectedReport._id" title="Current selection"></i>
|
||||
</a>
|
||||
<a ng-click="deleteReport(report)" class="action">
|
||||
<i class="icon-trash" title="Delete permanently"></i>
|
||||
</a>
|
||||
<div class="div-table-row"
|
||||
ng-repeat="bug in pageItems()"
|
||||
ng-animate="{ enter: 'example-repeat-enter',
|
||||
leave: 'example-repeat-leave',
|
||||
move: 'example-repeat-move'}">
|
||||
<div class="div-table-cell" ng-click="toggleSolved(bug)">
|
||||
<span title="Unsolved bug" ng-hide="bug.value.solved"><i class="icon-bug-unsolved"></i></span>
|
||||
<span title="Solved bug" ng-show="bug.value.solved"><i class="icon-bug-solved"></i></span>
|
||||
</div>
|
||||
<span title="Crash date" class="div-table-cell label label-info">{{report.displayDate}}</span>
|
||||
<span title="Application version name" class="div-table-cell label label-warning">{{report.value.application_version_name}}</span>
|
||||
<span title="Android verion" class="div-table-cell label label-success">{{report.value.android_version}}</span>
|
||||
<span title="Device" class="div-table-cell label">{{report.value.device}}</span>
|
||||
<div title="Latest report" class="div-table-cell label label-info">{{bug.latest}}</div>
|
||||
<div title="Number of reports" class="div-table-cell label">{{bug.value.count}}</div>
|
||||
<div title="Application version code" class="div-table-cell label label-warning">{{bug.key[0]}}</div>
|
||||
<div class="div-table-cell exceptions">
|
||||
<span title="Exception" class="label label-important">{{report.value.signature.digest}}</span>
|
||||
<span title="Root exception" class="label label-inverse" ng-show="report.value.signature.rootCause">Caused by: {{report.value.signature.rootCause}}</span>
|
||||
<span title="Exception" class="label label-important">{{bug.key[1]}}</span><br/>
|
||||
<span title="Root exception" class="label label-inverse" ng-show="bug.key[2]">Caused by: {{bug.key[2]}}</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<span paginator items="bugsList | filter:shouldBeDisplayed | orderBy:'value.latest':true" pageSize="bugsCount"></span>
|
||||
<ul class="pager">
|
||||
<li class="previous" ng-show="previousStartKeys.length > 0">
|
||||
<a ng-click="getPreviousPage()"><i class="icon-chevron-left"></i> Newer</a>
|
||||
@ -63,6 +65,5 @@
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
<report-details report="selectedReport" acralyzer="acralyzer"></report-details>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -75,8 +75,6 @@
|
||||
</div>
|
||||
<div class="div-table-row"
|
||||
ng-repeat="bug in bugs | filter:shouldBeDisplayed | orderBy:'value.latest':true | limitTo:bugsLimit"
|
||||
ng-class-odd="'odd'"
|
||||
ng-class-even="'even'"
|
||||
ng-animate="{ enter: 'example-repeat-enter',
|
||||
leave: 'example-repeat-leave',
|
||||
move: 'example-repeat-move'}">
|
||||
|
@ -19,23 +19,25 @@
|
||||
(function(acralyzerConfig,angular,acralyzer,acralyzerEvents) {
|
||||
"use strict";
|
||||
|
||||
function ReportsBrowserCtrl($scope, ReportsStore, $routeParams) {
|
||||
function BugsBrowserCtrl($scope, ReportsStore, $routeParams) {
|
||||
if($routeParams.app) {
|
||||
console.log("ReportsBrowser: Direct access to app " + $routeParams.app);
|
||||
console.log("BugsBrowser: Direct access to app " + $routeParams.app);
|
||||
$scope.acralyzer.setApp($routeParams.app);
|
||||
} else {
|
||||
console.log("ReportsBorwser: Access to default app " + acralyzerConfig.defaultApp);
|
||||
console.log("BugsBorwser: Access to default app " + acralyzerConfig.defaultApp);
|
||||
$scope.acralyzer.setApp(acralyzerConfig.defaultApp);
|
||||
}
|
||||
|
||||
console.log("Init ReportsBrowserCtrl");
|
||||
$scope.reportsCount = 15;
|
||||
console.log("Init BugsBrowserCtrl");
|
||||
$scope.bugsList = [];
|
||||
$scope.bugsCount = 15;
|
||||
$scope.hideSolvedBugs = true;
|
||||
$scope.previousStartKeys = [];
|
||||
$scope.selectedReport = "";
|
||||
$scope.selectedBug = "";
|
||||
$scope.startKey = null;
|
||||
$scope.nextKey = null;
|
||||
$scope.startNumber = 1;
|
||||
$scope.endNumber = $scope.reportsCount;
|
||||
$scope.endNumber = $scope.bugsCount;
|
||||
$scope.fullSearch = false;
|
||||
$scope.loading = true;
|
||||
$scope.noFilter = { value: "false", label: "No filter"};
|
||||
@ -63,42 +65,55 @@
|
||||
$scope.getData();
|
||||
};
|
||||
|
||||
$scope.getData = function() {
|
||||
$scope.loading = true;
|
||||
var successHandler = function(data) {
|
||||
// Success Handler
|
||||
console.log("Refresh data for latest reports");
|
||||
$scope.reports = data.rows;
|
||||
$scope.totalReports = data.total_rows;
|
||||
for(var row = 0; row < $scope.reports.length; row++) {
|
||||
if($scope.filterName === $scope.noFilter && $scope.filterValue === $scope.noFilterValue) {
|
||||
$scope.reports[row].displayDate = moment($scope.reports[row].key).fromNow();
|
||||
} else {
|
||||
$scope.reports[row].displayDate = moment($scope.reports[row].key[1]).fromNow();
|
||||
var mergeBugsLists = function(list1, list2) {
|
||||
var bugslist = {};
|
||||
for(var i1 = 0; i1 < list1.length; i1++) {
|
||||
bugslist[list1[i1].id] = {idxlist1: i1};
|
||||
}
|
||||
for(var i2 = 0; i2 < list2.length; i2++) {
|
||||
if(!bugslist[list2[i2].id]){
|
||||
// Mark bug as not found in list1
|
||||
bugslist[list2[i2].id] = {idxlist1: -1};
|
||||
}
|
||||
bugslist[list2[i2].id].idxlist2 = i2;
|
||||
}
|
||||
for(var iBugs in bugslist) {
|
||||
if(bugslist[iBugs].idxlist1 < 0 && bugslist[iBugs].idxlist2 >= 0) {
|
||||
// New bug
|
||||
list1.push(list2[bugslist[iBugs].idxlist2]);
|
||||
} else if (bugslist[iBugs].idxlist1 >= 0 && bugslist[iBugs].idxlist2 < 0) {
|
||||
// Deleted bug
|
||||
list1.splice(bugslist[iBugs].idxlist1, 1);
|
||||
} else if(bugslist[iBugs].idxlist1 >= 0 && bugslist[iBugs].idxlist2 >= 0) {
|
||||
if(!list1[bugslist[iBugs].idxlist1].equals(list2[bugslist[iBugs].idxlist2])) {
|
||||
// Updated bug
|
||||
list1[bugslist[iBugs].idxlist1].updateWithBug(list2[bugslist[iBugs].idxlist2]);
|
||||
}
|
||||
}
|
||||
|
||||
// If there are more rows, here is the key to the next page
|
||||
$scope.nextKey =data.next_row ? data.next_row.key : null;
|
||||
$scope.startNumber = ($scope.previousStartKeys.length * $scope.reportsCount) + 1;
|
||||
$scope.endNumber = $scope.startNumber + $scope.reports.length - 1;
|
||||
console.log($scope);
|
||||
$scope.loading = false;
|
||||
};
|
||||
|
||||
var errorHandler = function(response, getResponseHeaders){
|
||||
// Error Handler
|
||||
$scope.reports=[];
|
||||
$scope.totalReports="";
|
||||
};
|
||||
|
||||
if($scope.filterName === $scope.noFilter || $scope.filterValue === $scope.noFilterValue) {
|
||||
ReportsStore.reportsList($scope.startKey, $scope.reportsCount, $scope.fullSearch, successHandler, errorHandler);
|
||||
} else {
|
||||
ReportsStore.filteredReportsList($scope.filterName.value, $scope.filterValue.value,$scope.startKey, $scope.reportsCount, $scope.fullSearch, successHandler, errorHandler);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
$scope.getData = function() {
|
||||
$scope.loading = true;
|
||||
ReportsStore.bugsList(function(data) {
|
||||
console.log("Refresh data for latest bugs");
|
||||
console.log(data);
|
||||
mergeBugsLists($scope.bugsList, data.rows);
|
||||
$scope.totalBugs = data.total_rows;
|
||||
for(var row = 0; row < $scope.bugsList.length; row++) {
|
||||
$scope.bugsList[row].latest = moment($scope.bugsList[row].value.latest).fromNow();
|
||||
}
|
||||
$scope.loading = false;
|
||||
},
|
||||
function(response, getResponseHeaders){
|
||||
$scope.bugsList=[];
|
||||
$scope.totalBugs="";
|
||||
$scope.loading = false;
|
||||
});
|
||||
|
||||
};
|
||||
|
||||
$scope.changeFilterValues = function() {
|
||||
|
||||
if($scope.filterName === $scope.noFilter) {
|
||||
@ -126,6 +141,22 @@
|
||||
}
|
||||
};
|
||||
|
||||
$scope.toggleSolved = function(bug) {
|
||||
console.log("let's mark this bug as solved:");
|
||||
console.log(bug);
|
||||
ReportsStore.toggleSolved(bug, function(data){
|
||||
console.log(data);
|
||||
});
|
||||
};
|
||||
|
||||
$scope.shouldBeDisplayed = function(bug) {
|
||||
if($scope.hideSolvedBugs && bug.value.solved) {
|
||||
return false;
|
||||
} else {
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
$scope.filterValueSelected = function() {
|
||||
// reset pagination
|
||||
$scope.startKey = null;
|
||||
@ -134,31 +165,12 @@
|
||||
$scope.getData();
|
||||
};
|
||||
|
||||
$scope.loadReport = function(report) {
|
||||
$scope.selectedReport = ReportsStore.reportDetails(report.id, function(data) {
|
||||
data.readableUptime = moment.duration(data.uptime, 'seconds').humanize();
|
||||
data.formatedCrashDate = moment(data.USER_CRASH_DATE).format('LLL');
|
||||
data.formatedTimestamp = moment(data.timestamp).format('LLL');
|
||||
});
|
||||
};
|
||||
|
||||
$scope.deleteReport = function(report) {
|
||||
if($scope.selectedReport === report) {
|
||||
$scope.selectedReport = "";
|
||||
}
|
||||
|
||||
ReportsStore.deleteReport(report, function(data) {
|
||||
var index = $scope.reports.indexOf(report);
|
||||
$scope.reports.splice(index, 1);
|
||||
});
|
||||
};
|
||||
|
||||
$scope.$on(acralyzerEvents.LOGGED_IN, $scope.getData);
|
||||
$scope.$on(acralyzerEvents.LOGGED_OUT, $scope.getData);
|
||||
$scope.getData();
|
||||
}
|
||||
|
||||
|
||||
acralyzer.controller('ReportsBrowserCtrl', ["$scope", "ReportsStore", "$routeParams", ReportsBrowserCtrl]);
|
||||
acralyzer.controller('BugsBrowserCtrl', ["$scope", "ReportsStore", "$routeParams", BugsBrowserCtrl]);
|
||||
|
||||
})(window.acralyzerConfig,window.angular,window.acralyzer,window.acralyzerEvents);
|
||||
|
@ -25,6 +25,7 @@
|
||||
$routeProvider.
|
||||
when('/dashboard/:app', {templateUrl: 'partials/dashboard.html', controller: 'DashboardCtrl', activetab: "dashboard"}).
|
||||
when('/reports-browser/:app', {templateUrl: 'partials/reports-browser.html', controller: 'ReportsBrowserCtrl', activetab: "reports-browser"}).
|
||||
when('/bugs-browser/:app', {templateUrl: 'partials/bugs-browser.html', controller: 'BugsBrowserCtrl', activetab: "bugs-browser"}).
|
||||
when('/report-details/:app/:reportId', {templateUrl: 'partials/report-details.html', controller: 'ReportDetailsCtrl', activetab: "none"}).
|
||||
when('/admin/:app', {templateUrl: 'partials/admin.html', controller: 'AdminCtrl', activetab: "admin"}).
|
||||
otherwise({redirectTo: '/dashboard/' + acralyzerConfig.defaultApp});
|
||||
@ -162,4 +163,72 @@
|
||||
}
|
||||
};
|
||||
});
|
||||
|
||||
/* http://www.frangular.com/2012/12/pagination-cote-client-directive-angularjs.html */
|
||||
acralyzer.directive('paginator', function () {
|
||||
var pageSizeLabel = "Page size";
|
||||
return {
|
||||
priority: 0,
|
||||
restrict: 'A',
|
||||
scope: {items: '&'},
|
||||
template:
|
||||
'<button ng-disabled="isFirstPage()" ng-click="decPage()" class="btn">< newer</button>' +
|
||||
pageSizeLabel + ' <select ng-model="paginator.pageSize" ng-options="size for size in pageSizeList" class="input-small"></select>' +
|
||||
'<button ng-disabled="isLastPage()" ng-click="incPage()" class="btn">older ></button>',
|
||||
replace: false,
|
||||
compile: function compile(tElement, tAttrs, transclude) {
|
||||
return {
|
||||
pre: function preLink(scope, iElement, iAttrs, controller) {
|
||||
scope.pageSizeList = [5, 10, 20, 50, 100];
|
||||
scope.paginator = {
|
||||
pageSize: 5,
|
||||
currentPage: 0
|
||||
};
|
||||
|
||||
scope.isFirstPage = function () {
|
||||
return scope.paginator.currentPage === 0;
|
||||
};
|
||||
scope.isLastPage = function () {
|
||||
return scope.paginator.currentPage >= scope.items().length / scope.paginator.pageSize - 1;
|
||||
};
|
||||
scope.incPage = function () {
|
||||
if (!scope.isLastPage()) {
|
||||
scope.paginator.currentPage++;
|
||||
}
|
||||
};
|
||||
scope.decPage = function () {
|
||||
if (!scope.isFirstPage()) {
|
||||
scope.paginator.currentPage--;
|
||||
}
|
||||
};
|
||||
scope.firstPage = function () {
|
||||
scope.paginator.currentPage = 0;
|
||||
};
|
||||
scope.numberOfPages = function () {
|
||||
return Math.ceil(scope.items().length / scope.paginator.pageSize);
|
||||
};
|
||||
scope.$watch('paginator.pageSize', function(newValue, oldValue) {
|
||||
if (newValue !== oldValue) {
|
||||
scope.firstPage();
|
||||
}
|
||||
});
|
||||
|
||||
// ---- Functions available in parent scope -----
|
||||
|
||||
scope.$parent.firstPage = function () {
|
||||
scope.firstPage();
|
||||
};
|
||||
// Function that returns the reduced items list, to use in ng-repeat
|
||||
scope.$parent.pageItems = function () {
|
||||
var start = scope.paginator.currentPage * scope.paginator.pageSize;
|
||||
var limit = scope.paginator.pageSize;
|
||||
console.log(scope.items());
|
||||
return scope.items().slice(start, start + limit);
|
||||
};
|
||||
},
|
||||
post: function postLink(scope, iElement, iAttrs, controller) {}
|
||||
};
|
||||
}
|
||||
};
|
||||
});
|
||||
})(window.acralyzerConfig, window.angular, window.jQuery, window.acralyzerEvents);
|
||||
|
@ -262,4 +262,19 @@ report-summary .label-androidversion {
|
||||
.icon-phone {
|
||||
background-image: url(../img/device-black.png);
|
||||
background-position: 0px;
|
||||
}
|
||||
|
||||
.icon-bug-unsolved {
|
||||
background-image: url(../img/bug.png);
|
||||
background-position: 0px;
|
||||
}
|
||||
|
||||
.icon-bug-unsolved:hover, .icon-bug-solved:hover {
|
||||
background-image: url(../img/bug-rollover.png);
|
||||
background-position: 0px;
|
||||
}
|
||||
|
||||
.icon-bug-solved {
|
||||
background-image: url(../img/bug-solved.png);
|
||||
background-position: 0px;
|
||||
}
|
Loading…
Reference in New Issue
Block a user