diff --git a/js/app/controllers/EpnTapModule.js b/js/app/controllers/EpnTapModule.js
index 01f79ac..f6b7324 100644
--- a/js/app/controllers/EpnTapModule.js
+++ b/js/app/controllers/EpnTapModule.js
@@ -60,8 +60,6 @@ function isLatest(newStrDate, oldStrDate) {
 	}
 }
 
-
-
 Ext.define('amdaDesktop.EpnTapModule', {
 
 	extend: 'amdaDesktop.AmdaModule',
@@ -90,8 +88,6 @@ Ext.define('amdaDesktop.EpnTapModule', {
 		this.productTypeDict = JSON.parse(loadTextFileAjaxSync('../../generic_data/EpnTapData/dataproduct_types.json', 'application/json'));
 		this.mimetypeDict = JSON.parse(loadTextFileAjaxSync('../../generic_data/EpnTapData/mimetypes.json', 'application/json'));
 
-		this.currentPage = 0;
-		this.nbRows = 0;
 		this.select = Array();
 		this.filter = Array();
 
@@ -110,15 +106,20 @@ Ext.define('amdaDesktop.EpnTapModule', {
 		this.dataProdutTypeCB = Ext.getCmp('productTypeCB');
 		this.targetClassCB = Ext.getCmp('targetClassCB');
 		this.targetNameCB = Ext.getCmp('targetNameCB');
+		this.startTimeDF = Ext.getCmp('startTimeDF');
+		this.stopTimeDF = Ext.getCmp('stopTimeDF');
+
 		this.servicesGrid = Ext.getCmp('servicesGrid');
 		this.granulesGrid = Ext.getCmp('granulesGrid');
-		this.pageLabel = Ext.getCmp('pageLb');
+
+		this.rowsPerPageNf = Ext.getCmp('rowsPerPageNf');
+		this.currentPageLb = Ext.getCmp('currentPageLb');
+		this.totalPagesLb = Ext.getCmp('totalPagesLb');
+
 		this.previousBtn = Ext.getCmp('previousPageBtn');
 		this.nextBtn = Ext.getCmp('nextPageBtn');
 		this.firstBtn = Ext.getCmp('firstPageBtn');
 		this.lastBtn = Ext.getCmp('lastPageBtn');
-		this.startTimeDF = Ext.getCmp('startTimeDF');
-		this.stopTimeDF = Ext.getCmp('stopTimeDF');
 
 		this.dataProdutTypeCB.getStore().removeAll();
 		this.dataProdutTypeCB.getStore().add({'id': 'all', 'name': 'All data product types'});
@@ -130,7 +131,6 @@ Ext.define('amdaDesktop.EpnTapModule', {
 			}
 		}
 		this.dataProdutTypeCB.select('all');
-		this
 
 		this.targetClassCB.getStore().removeAll();
 		this.targetClassCB.getStore().add({'id': 'all', 'name': 'All target names'});
@@ -161,7 +161,6 @@ Ext.define('amdaDesktop.EpnTapModule', {
 				this.targetClassCB.getStore().add({'id': Object.keys(targetClasses)[0], 'name': prettify(Object.keys(targetClasses)[0])});
 				this.targetClassCB.disable();
 				this.targetClassCB.select(this.targetClassCB.getStore().getAt(0)['internalId']);
-				this.onTargetClassCB();
 			} else {
 				this.targetClassCB.getStore().add({'id': 'all', 'name': allPrettify(this.productTypeDict[this.dataProdutTypeCB.value])});
 				for (var targetClassId in targetClasses) {
@@ -207,44 +206,75 @@ Ext.define('amdaDesktop.EpnTapModule', {
 	},
 
 	onRowsPerPageChanged: function() {
-		var rowsPerPage = Ext.getCmp('rowsPerPageNf').value;
-		var nbPages = Math.ceil(this.nbRows / rowsPerPage);
-		this.currentPage = 1;
-		this.pageLabel.setText('1/' + nbPages);
-		this.previousPageBtn.setDisabled(true);
-		this.firstPageBtn.setDisabled(true);
-		if (nbPages==1) {
-			this.nextPageBtn.setDisabled(true);
-			this.lastPageBtn.setDisabled(true);
-		} else {
-			this.nextPageBtn.setDisabled(false);
-			this.lastPageBtn.setDisabled(false);
-		}
+		console.log("rows per page: " + this.rowsPerPageNf.value);
 	},
 
 	// *** Buttons events ***
 
 	onFirstPageBtnClicked: function() {
-		var limit = this.rowsPerPageNf.value;
+		this.currentPageLb.setText('1');
+
+		this.nextBtn.setDisabled(false);
+		this.lastBtn.setDisabled(false);
+		this.firstBtn.setDisabled(true);
+		this.previousBtn.setDisabled(true);
+
 		var selectedServiceURL = this.services[this.selectedServiceId]['accessurl'];
+		var limit = this.rowsPerPageNf.value;
+		var offset = '0';
+
 		AmdaAction.epnTapGetGranules(this.selectedServiceId, selectedServiceURL, this.filter, this.select, limit, offset, this.fillGranules);
 	},
 
 	onPreviousPageBtnClicked: function() {
-		var limit = this.rowsPerPageNf.value;
+		var newPageNumber = Number(this.currentPageLb.text) - 1;
+		this.currentPageLb.setText('' + newPageNumber);
+
+		this.nextBtn.setDisabled(false);
+		this.lastBtn.setDisabled(false);
+		if (this.currentPageLb.text === '1') {
+			this.previousBtn.setDisabled(true);
+			this.firstBtn.setDisabled(true);
+		}
+
 		var selectedServiceURL = this.services[this.selectedServiceId]['accessurl'];
+		var limit = this.rowsPerPageNf.value;
+		var offset = '' + (newPageNumber-1) * Number(this.rowsPerPageNf.value);
+
 		AmdaAction.epnTapGetGranules(this.selectedServiceId, selectedServiceURL, this.filter, this.select, limit, offset, this.fillGranules);
 	},
 
 	onNextPageBtnClicked: function() {
-		var limit = this.rowsPerPageNf.value;
+		var newPageNumber = Number(this.currentPageLb.text) + 1;
+		this.currentPageLb.setText('' + newPageNumber);
+
+		this.previousBtn.setDisabled(false);
+		this.firstBtn.setDisabled(false);
+		if (this.currentPageLb.text === this.totalPagesLb.text) {
+			this.nextBtn.setDisabled(true);
+			this.lastBtn.setDisabled(true);
+		}
+
 		var selectedServiceURL = this.services[this.selectedServiceId]['accessurl'];
+		var limit = this.rowsPerPageNf.value;
+		var offset = '' + (newPageNumber-1) * Number(this.rowsPerPageNf.value);
+
 		AmdaAction.epnTapGetGranules(this.selectedServiceId, selectedServiceURL, this.filter, this.select, limit, offset, this.fillGranules);
 	},
 
 	onLastPageBtnClicked: function() {
-		var limit = this.rowsPerPageNf.value;
+		var newPageNumber = this.totalPagesLb.text;
+		this.currentPageLb.setText('' + newPageNumber);
+
+		this.previousBtn.setDisabled(false);
+		this.firstBtn.setDisabled(false);
+		this.nextBtn.setDisabled(true);
+		this.lastBtn.setDisabled(true);
+
 		var selectedServiceURL = this.services[this.selectedServiceId]['accessurl'];
+		var limit = this.rowsPerPageNf.value;
+		var offset = '' + (newPageNumber-1) * Number(this.rowsPerPageNf.value);
+
 		AmdaAction.epnTapGetGranules(this.selectedServiceId, selectedServiceURL, this.filter, this.select, limit, offset, this.fillGranules);
 	},
 
@@ -273,10 +303,9 @@ Ext.define('amdaDesktop.EpnTapModule', {
 			Ext.getCmp('stopTimeDF').getRawValue() !== '' ? Ext.getCmp('stopTimeDF').getRawValue() : null // stop time
 		);
 
-		var limit = Ext.getCmp('rowsPerPageNf').value;
-
+		var limit = this.rowsPerPageNf.value;
+		AmdaAction.epnTapGetNbRows(selectedServiceId, selectedServiceURL, this.filter, this.updateNbRows);
 		AmdaAction.epnTapGetGranules(selectedServiceId, selectedServiceURL, this.filter, this.select, limit, 0, this.fillGranules);
-		AmdaAction.epnTapGetNbRows(selectedServiceId, selectedServiceURL, this.filter, this.updateNbResult);
 	},
 
 	onGranuleSelected: function() {
@@ -285,7 +314,26 @@ Ext.define('amdaDesktop.EpnTapModule', {
 
 	// *** Other functions ***
 
+	updateNbRows: function(nb_results) {
+		/* /!\ Can not get `this`. */
+		var totalPages = '' + Math.ceil(Number(nb_results) / Ext.getCmp('rowsPerPageNf').value);
+
+		Ext.getCmp('currentPageLb').setText('1');
+		Ext.getCmp('totalPagesLb').setText(totalPages);
+		Ext.getCmp('previousPageBtn').setDisabled(true);
+		Ext.getCmp('firstPageBtn').setDisabled(true);
+		if (totalPages === '1') {
+			Ext.getCmp('nextPageBtn').setDisabled(true);
+			Ext.getCmp('lastPageBtn').setDisabled(true);
+		} else {
+			Ext.getCmp('nextPageBtn').setDisabled(false);
+			Ext.getCmp('lastPageBtn').setDisabled(false);
+		}
+	},
+
 	fillGranules: function(granules) {
+		/* /!\ Can not get `this`. */
+
 		if (granules == null) {
 			console.log("There is no granules to add.");
 		} else {
@@ -299,11 +347,6 @@ Ext.define('amdaDesktop.EpnTapModule', {
 		}
 	},
 
-	updateNbResult: function(nb_results) {
-		console.log("updateNbResult");
-		console.log(nb_results);
-	},
-
 	updateServices: function() {
 		this.servicesGrid.getStore().removeAll();
 		this.granulesGrid.getStore().removeAll();
diff --git a/js/app/views/EpnTapUI.js b/js/app/views/EpnTapUI.js
index 033a544..140e95e 100644
--- a/js/app/views/EpnTapUI.js
+++ b/js/app/views/EpnTapUI.js
@@ -283,24 +283,37 @@ Ext.define('amdaUI.EpnTapUI', {
 				xtype: 'label',
 				text: 'Page:'
 			}, {
-				id: 'previousPageBtn',
+				id: 'firstPageBtn',
 				text: '|<',
+				tooltip: 'First page',
 				handler: function() { epnTapModule.onFirstPageBtnClicked(); }
 			}, {
-				id: 'firstPageBtn',
+				id: 'previousPageBtn',
 				text: '<',
+				tooltip: 'Previous page',
 				handler: function() { epnTapModule.onPreviousPageBtnClicked(); }
 			}, {
 				xtype: 'label',
-				id: 'pageLb',
-				text: '0/0'
+				id: 'currentPageLb',
+				tooltip: 'Current page',
+				text: '-'
+			}, {
+				xtype: 'label',
+				text: '/'
+			}, {
+				xtype: 'label',
+				id: 'totalPagesLb',
+				tooltip: 'Total pages',
+				text: '-'
 			}, {
 				id: 'nextPageBtn',
 				text: '>',
+				tooltip: 'Next page',
 				handler: function() { epnTapModule.onNextPageBtnClicked(); }
 			}, {
 				id: 'lastPageBtn',
 				text: '>|',
+				tooltip: 'Last page',
 				handler: function() { epnTapModule.onLastPageBtnClicked(); }
 			}]
 		});
diff --git a/php/classes/EpnTapMgr.php b/php/classes/EpnTapMgr.php
index a7b75d7..2f471c2 100644
--- a/php/classes/EpnTapMgr.php
+++ b/php/classes/EpnTapMgr.php
@@ -28,12 +28,12 @@ class EpnTapMgr {
 		return ($date == '00/00/0000') ? '' : $date;
 	}
 
-	public function createFilter($target_name, $dataproduct_type, $time_min, $time_max) {
+	public function createFilter($dataproduct_type, $target_name, $time_min, $time_max) {
 		$filter = array();
-		if($target_name)
-			array_push($filter, "target_name = '$target_name'");
 		if($dataproduct_type)
 			array_push($filter, "dataproduct_type = '$dataproduct_type'");
+		if($target_name)
+			array_push($filter, "target_name = '$target_name'");
 		if($time_min)
 			array_push($filter, "time_min <= " . $this->dateToJD($time_min));
 		if($time_max)
@@ -52,7 +52,7 @@ class EpnTapMgr {
 		return $result;
 	}
 
-	/* filter order: $target_name, $time_min, $time_max, $table_name, $access_url */
+	/* filter order: product type, target name, time min, time max */
 	public function getGranules($table_name, $access_url, $filter, $select, $limit, $offset) {
 		$query = "SELECT TOP $limit " . join(', ', $select) . " FROM $table_name.epn_core " . $this->createFilter($filter[0], $filter[1], $filter[2], $filter[3]) . " OFFSET $offset";
 		// return $query;
@@ -64,6 +64,7 @@ class EpnTapMgr {
 		return $result;
 	}
 
+	/* filter order: product type, target name, time min, time max */
 	public function getNbRows($table_name, $access_url, $filter) {
 		$query = "SELECT COUNT(*) AS nb_rows FROM $table_name.epn_core " . $this->createFilter($filter[0], $filter[1], $filter[2], $filter[3]);
 		// return $query;
--
libgit2 0.21.2