diff --git a/taiga_tasks/remote/js/taiga_tasks_api.js b/taiga_tasks/remote/js/taiga_tasks_api.js
index b35e7ae..4112be4 100644
--- a/taiga_tasks/remote/js/taiga_tasks_api.js
+++ b/taiga_tasks/remote/js/taiga_tasks_api.js
@@ -18,23 +18,24 @@
* ----------------------------------------------------------------------------------
* Get taiga AUTH_TOKEN used in all subsequent taiga API calls
*/
-function getAuthToken(website, project, adminUsername, adminPassword, users) {
+function getAuthToken(taigaParams) {
$.ajax({
method: "POST",
- url: website + '/api/v1/auth',
+ url: taigaParams.website + '/api/v1/auth',
data: {
"type": "normal",
- "username": adminUsername,
- "password": adminPassword
+ "username": taigaParams.adminUsername,
+ "password": taigaParams.adminPassword
},
success: function(json) {
- showSuccessAlert("Taiga authentication succeeded for user " + adminUsername + ".");
- getProjectID(website, project, json.auth_token, users);
+ showSuccessAlert("Taiga authentication succeeded for user " + taigaParams.adminUsername + ".");
+ taigaParams.authToken = json.auth_token;
+ getProjectID(taigaParams);
},
error: function(jqXHR, textStatus, errorThrown) {
console.log(textStatus, errorThrown);
- showErrorAlert("Taiga authentication failed for user " + adminUsername + " because of incorrect username or password.");
+ showErrorAlert("Taiga authentication failed for user " + taigaParams.adminUsername + " because of incorrect username or password.");
}
});
};
@@ -43,16 +44,17 @@ function getAuthToken(website, project, adminUsername, adminPassword, users) {
* ----------------------------------------------------------------------------------
* Get taiga project ID
*/
-function getProjectID(website, project, authToken, users) {
+function getProjectID(taigaParams) {
$.ajax({
method: "GET",
- url: website + '/api/v1/resolver?project=' + project,
+ url: taigaParams.website + '/api/v1/resolver?project=' + taigaParams.project,
beforeSend: function(xhr) {
- xhr.setRequestHeader('Authorization', 'Bearer ' + authToken);
+ xhr.setRequestHeader('Authorization', 'Bearer ' + taigaParams.authToken);
},
success: function(json) {
showSuccessAlert("ProjectID retrieval succeeded.");
- getProjectName(website, authToken, json.project, users);
+ taigaParams.projectID = json.project;
+ getProjectName(taigaParams);
},
error: function(jqXHR, textStatus, errorThrown) {
console.log(textStatus, errorThrown);
@@ -65,16 +67,17 @@ function getProjectID(website, project, authToken, users) {
* ----------------------------------------------------------------------------------
* Get taiga project name
*/
-function getProjectName(website, authToken, projectID, users) {
+function getProjectName(taigaParams) {
$.ajax({
method: "GET",
- url: website + '/api/v1/projects/' + projectID,
+ url: taigaParams.website + '/api/v1/projects/' + taigaParams.projectID,
beforeSend: function(xhr) {
- xhr.setRequestHeader('Authorization', 'Bearer ' + authToken);
+ xhr.setRequestHeader('Authorization', 'Bearer ' + taigaParams.authToken);
},
success: function(json) {
showSuccessAlert("Project name retrieval succeeded.");
- processUsers(website, authToken, projectID, json.name, users);
+ taigaParams.projectName = json.name;
+ processUsers(taigaParams);
},
error: function(jqXHR, textStatus, errorThrown) {
console.log(textStatus, errorThrown);
@@ -87,11 +90,19 @@ function getProjectName(website, authToken, projectID, users) {
* ----------------------------------------------------------------------------------
* Get taiga user(s)
*/
-function processUsers(website, authToken, projectID, projectName, users) {
+function processUsers(taigaParams) {
- users.forEach(function(element, i) {
- $('#container').append('
');
- getUserID(website, authToken, projectID, projectName, element, i);
+ (taigaParams.users).forEach(function(userName, index) {
+
+ // clear all system alerts, as subsequent alerts will be user-specific
+ //
+ clearAlerts();
+
+ getUserID(taigaParams, {
+ userName: userName, // user name
+ index: index + 1, // index of user used for displaying into HTML divs
+ userID: 0 // user ID
+ });
});
}
@@ -100,24 +111,26 @@ function processUsers(website, authToken, projectID, projectName, users) {
* ----------------------------------------------------------------------------------
* Get username id
*/
-function getUserID(website, authToken, projectID, projectName, username, divIndex) {
+function getUserID(taigaParams, userParams) {
$.ajax({
method: "GET",
- url: website + '/api/v1/users?project=' + projectID,
+ url: taigaParams.website + '/api/v1/users?project=' + taigaParams.projectID,
beforeSend: function(xhr) {
- xhr.setRequestHeader('Authorization', 'Bearer ' + authToken);
+ xhr.setRequestHeader('Authorization', 'Bearer ' + taigaParams.authToken);
},
success: function(json) {
- showSuccessAlert("User ID retrieval for " + username + " succeeded.");
+ showSuccessAlert("User ID retrieval for " + userParams.userName + " succeeded.", userParams.index);
var result = $.grep(json, function(element, index) {
- return element.username == username;
+ return element.username == userParams.userName;
});
- getUserStories(website, authToken, projectID, projectName, result[0].id, divIndex, getResults);
+
+ userParams.userID = result[0].id;
+ getUserStories(taigaParams, userParams, getResults);
},
error: function(jqXHR, textStatus, errorThrown) {
console.log(textStatus, errorThrown);
- showErrorAlert("Unable to retrieve user ID for " + username + ".");
+ showErrorAlert("Unable to retrieve user ID for " + userParams.userName + ".");
}
});
};
@@ -126,52 +139,69 @@ function getUserID(website, authToken, projectID, projectName, username, divInde
* ----------------------------------------------------------------------------------
* Get user stories
*/
-function getUserStories(website, authToken, projectID, projectName, userID, divIndex, callback) {
+function getUserStories(taigaParams, userParams, callback) {
+
+ // include/exclude incomplete (in progress) tasks in userstories query
+ //
+ var closedTasks = "";
+ if (!taigaParams.showIncompleteTasks) {
+ closedTasks = '\&is_closed=true';
+ };
+
$.ajax({
method: "GET",
- url: website + '/api/v1/userstories?project=' + projectID + '\&assigned_to=' + userID,
+ url: taigaParams.website + '/api/v1/userstories?project=' + taigaParams.projectID + '\&assigned_to=' + userParams.userID + closedTasks,
beforeSend: function(xhr) {
- xhr.setRequestHeader('Authorization', 'Bearer ' + authToken);
+ xhr.setRequestHeader('Authorization', 'Bearer ' + taigaParams.authToken);
},
success: function(json) {
var newItem = [];
var callbackCount = json.length;
- showSuccessAlert("User stories retrieval succeeded.");
+ showSuccessAlert("User stories retrieval succeeded.", userParams.index);
// build newItem array from JSON returns
//
var json = $.map(json, function(item) {
- // get custom fields (actual_points) and include in final JSON return
- // if no attributes_values, then set to null (user didn't set a value)
+ // check if story date is within requested date range
//
- getCustomFields(website, authToken, projectID, item.id).done(function(data) {
-
- var actualPoints = data.attributes_values[1];
-
- if (actualPoints === undefined) {
- actualPoints = null;
+ if ((item.modified_date < taigaParams.startDate) || (item.modified_date > taigaParams.endDate)) {
+ if (!--callbackCount) {
+ showInfoAlert("No user stories found matching date criteria for user " + userParams.userName + ".", userParams.index);
}
+ } else {
- newItem.push({
- estimated_points: item.total_points,
- subject: item.subject,
- story_id: item.id,
- full_name: item.assigned_to_extra_info.full_name_display,
- finish_date: item.finish_date,
- actual_points: actualPoints,
- project_name: projectName
- });
-
- // manage callback counts, given we don't know when all callbacks
- // have completed... when all callbacks return, continue
+ // get custom fields (actual_points) and include in final JSON return
+ // if no attributes_values, then set to null (user didn't set a value)
//
- if (!--callbackCount) {
- callback(newItem, divIndex);
- };
+ getCustomFields(taigaParams, userParams, item.id).done(function(data) {
+
+ var actualPoints = data.attributes_values[1];
+
+ if (actualPoints === undefined) {
+ actualPoints = null;
+ }
+
+ newItem.push({
+ estimated_points: item.total_points,
+ subject: item.subject,
+ story_id: item.id,
+ full_name: item.assigned_to_extra_info.full_name_display,
+ finish_date: item.finish_date,
+ actual_points: actualPoints,
+ project_name: taigaParams.projectName
+ });
+
+ // manage callback counts, given we don't know when all callbacks
+ // have completed... when all callbacks return, continue
+ //
+ if (!--callbackCount) {
+ callback(taigaParams, userParams, newItem);
+ };
- });
+ });
+ };
});
},
error: function(jqXHR, textStatus, errorThrown) {
@@ -185,15 +215,15 @@ function getUserStories(website, authToken, projectID, projectName, userID, divI
* ----------------------------------------------------------------------------------
* Get user story custom fields (e.g,. actual_points field)
*/
-function getCustomFields(website, authToken, projectID, storyID) {
+function getCustomFields(taigaParams, userParams, storyID) {
return $.ajax({
method: "GET",
- url: website + '/api/v1/userstories/custom-attributes-values/' + storyID + '?project=' + projectID,
+ url: taigaParams.website + '/api/v1/userstories/custom-attributes-values/' + storyID + '?project=' + taigaParams.projectID,
beforeSend: function(xhr) {
- xhr.setRequestHeader('Authorization', 'Bearer ' + authToken);
+ xhr.setRequestHeader('Authorization', 'Bearer ' + taigaParams.authToken);
},
success: function() {
- showSuccessAlert("Custom fields retrieval succeeded.");
+ showSuccessAlert("Custom fields retrieval succeeded.", userParams.index);
},
error: function(jqXHR, textStatus, errorThrown) {
console.log(textStatus, errorThrown);
@@ -311,7 +341,7 @@ function getDateTime() {
* ----------------------------------------------------------------------------------
* Get and process the resultng JSON file for highcharts (hc)
*/
-function getResults(json, divIndex) {
+function getResults(taigaParams, userParams, json) {
var results = processResults(json);
hcCategories = createResultsCategories(results);
@@ -322,23 +352,24 @@ function getResults(json, divIndex) {
// $('#debug').append('
=========Categories==========
' + JSON.stringify(hcCategories, null, 4));
// $('#debug').append('
=========Series==============
' + JSON.stringify(hcSeries));
- plotChart(results, hcCategories, hcSeries, hcDate, divIndex);
+ plotChart(taigaParams, userParams, hcCategories, hcSeries, hcDate, results);
};
/**
* ----------------------------------------------------------------------------------
* Plot data to highcharts object
*/
-function plotChart(data, categories, series, date, count) {
+function plotChart(taigaParams, userParams, categories, series, date, data) {
- $('#chart' + [count]).highcharts({
+ $('#container').append('
');
+ $('#chart' + [userParams.index]).highcharts({
title: {
- text: data[0]['full_name'] + ' : Task Activity Report'
+ text: data[0]['project_name'] + ' Project' + '
' + 'Task Activity Report for ' + data[0]['full_name']
},
subtitle: {
- text: data[0]['project_name'] + ' Project
' + 'Generated on ' + date
+ text: 'Activity Date Range: ' + (new Date(taigaParams.startDate)).toJSON().slice(0, 10) + ' to ' + (new Date(taigaParams.endDate)).toJSON().slice(0, 10) + '
' + 'Report Generated on ' + date
},
xAxis: {
@@ -364,8 +395,7 @@ function plotChart(data, categories, series, date, count) {
series: series
});
- clearAlerts(count);
-
+ clearAlerts(userParams.index);
};
/**
@@ -373,21 +403,29 @@ function plotChart(data, categories, series, date, count) {
* Display alerts to browser window
*/
-function showSuccessAlert(msg) {
- ShowAlert(msg, 0);
+function showSuccessAlert(msg, index) {
+ ShowAlert(msg, index, 0);
};
-function showErrorAlert(msg) {
- ShowAlert(msg, 1);
+function showErrorAlert(msg, index) {
+ ShowAlert(msg, index, 1);
};
-function ShowAlert(msg, type) {
+function showInfoAlert(msg, index) {
+ ShowAlert(msg, index, 2);
+};
- msgType = {
+function ShowAlert(msg, index, type) {
+
+ var msgType = {
class: "",
text: ""
};
+ if (typeof index == "undefined") {
+ index = 0;
+ }
+
switch (type) {
case 0:
msgType.class = "alert-success";
@@ -397,23 +435,34 @@ function ShowAlert(msg, type) {
msgType.class = "alert-danger";
msgType.text = "Error";
break;
+ case 2:
+ msgType.class = "alert-warning";
+ msgType.text = "Warning";
+ break;
default:
msgType.class = "alert-info";
- msgType.text = "Info";
+ msgType.text = "Information";
};
- $('#alerts').html("" + msgType.text + ": " + msg + "
");
+ var element = "" + msgType.text + ": " + msg + "
";
+
+ if ($("#alert" + index).length) {
+ $("#alert" + index).replaceWith(element);
+ } else {
+ $('#alerts').append(element);
+ }
};
/**
* ----------------------------------------------------------------------------------
- * Remove alerts after final chart is rendered
+ * Remove alerts after final chart(s) is rendered
*/
-function clearAlerts(count) {
+function clearAlerts(index) {
- if ($("div[id^='chart']").length - 1 == count) {
- $('#alert').remove();
- };
+ if (typeof index == "undefined") {
+ index = 0;
+ }
+ $('#alert' + index).remove();
};
diff --git a/taiga_tasks/remote/js/taiga_tasks_dlg.js b/taiga_tasks/remote/js/taiga_tasks_dlg.js
index a36da39..43eb0f6 100644
--- a/taiga_tasks/remote/js/taiga_tasks_dlg.js
+++ b/taiga_tasks/remote/js/taiga_tasks_dlg.js
@@ -14,8 +14,108 @@
---------------------------------------------------------------------------------------------------
*/
-angular.module('ui.bootstrap.demo', ['ngAnimate', 'ui.bootstrap']);
-angular.module('ui.bootstrap.demo').controller('ModalDemoCtrl', function($scope, $modal, $log) {
+var app = angular.module('taiga.tasks', ['ngAnimate', 'ui.bootstrap']);
+
+app.service('sharedProperties', function() {
+
+ var objectValue = {
+ dtStart: '',
+ dtEnd: ''
+ };
+
+ return {
+ setStartDate: function(startDate) {
+ objectValue.dtStart = startDate;
+ },
+ setEndDate: function(endDate) {
+ objectValue.dtEnd = endDate;
+ },
+ getStartDate: function() {
+ return objectValue.dtStart;
+ },
+ getEndDate: function() {
+ return objectValue.dtEnd;
+ },
+ }
+});
+
+app.controller('DatepickerDemoCtrl', function($scope, sharedProperties) {
+
+ $scope.today = function() {
+ var x = new Date();
+ x.setDate(1);
+ x.setHours(0, 0, 0, 0);
+ x.setMonth(x.getMonth());
+ $scope.dtStart = x;
+
+ x = new Date();
+ x.setHours(23, 59, 59, 999);
+ $scope.dtEnd = x;
+ };
+
+ $scope.today();
+
+ $scope.clear = function() {
+ $scope.dtStart = null;
+ $scope.dtEnd = null;
+ };
+
+ $scope.toggleMin = function() {
+ $scope.minDate = $scope.minDate ? null : new Date();
+ };
+
+ $scope.toggleMin();
+
+ $scope.maxDate = new Date(2020, 5, 22);
+
+ $scope.open = function($event, opened) {
+ $event.preventDefault();
+ $event.stopPropagation();
+ $scope.status[opened] = true;
+ };
+
+ $scope.$watch('dtStart', function() {
+ sharedProperties.setStartDate($scope.dtStart);
+ });
+
+ $scope.$watch('dtEnd', function() {
+ sharedProperties.setEndDate($scope.dtEnd);
+ });
+
+ $scope.dateOptions = {
+ formatYear: 'yy',
+ startingDay: 1
+ };
+
+ $scope.formats = ['dd-MMMM-yyyy', 'yyyy/MM/dd', 'dd.MM.yyyy', 'shortDate'];
+ $scope.format = $scope.formats[0];
+
+ $scope.status = {
+ opened: false
+ };
+
+});
+
+app.controller('ModalDemoCtrl', function($scope, $modal, $log, sharedProperties) {
+
+ function toTaigaFormat(d) {
+ function pad(n) {
+ return n < 10 ? '0' + n : n
+ }
+ return d.getUTCFullYear() + '-' +
+ pad(d.getUTCMonth() + 1) + '-' +
+ pad(d.getUTCDate()) + 'T' +
+ pad(d.getUTCHours()) + ':' +
+ pad(d.getUTCMinutes()) + ':' +
+ pad(d.getUTCSeconds()) + '+' + "0000"
+ // pad(d.getUTCMilliseconds())
+ };
+
+ $scope.dlgModel = {
+ username: "",
+ password: "",
+ radio: 1
+ };
$scope.checkModel = {
duane: false,
@@ -24,15 +124,10 @@ angular.module('ui.bootstrap.demo').controller('ModalDemoCtrl', function($scope,
richbl: false
};
- $scope.dlgModel = {
- username: "",
- password: ""
- };
-
var modalInstance = $modal.open({
backdrop: 'static',
keyboard: false,
- templateUrl: 'myModalContent.html',
+ templateUrl: 'taiga_tasks.html',
controller: 'ModalInstanceCtrl',
resolve: {
checkModel: function() {
@@ -41,15 +136,17 @@ angular.module('ui.bootstrap.demo').controller('ModalDemoCtrl', function($scope,
dlgModel: function() {
return $scope.dlgModel;
}
-
}
}).result.then(function() {
- checkResults = [];
+ var users = [];
+
+ var startDate = toTaigaFormat(sharedProperties.getStartDate());
+ var endDate = toTaigaFormat(sharedProperties.getEndDate());
angular.forEach($scope.checkModel, function(value, key) {
if (value) {
- checkResults.push(key);
+ users.push(key);
}
});
@@ -57,19 +154,28 @@ angular.module('ui.bootstrap.demo').controller('ModalDemoCtrl', function($scope,
// this is the interesting call that fires up the Taiga API through a series of Ajax calls into the
// Taiga project, retrieves and processes the information, and ultimately displays the resulting charts
//
- getAuthToken(
- 'http://www.website.com', // the taiga website to gather tasks
- 'project_slug', // the taiga project slug (not project name)
- $scope.dlgModel.username, // project user with admin permissions (to access task details)
- $scope.dlgModel.password, // project user password
- checkResults // users to gather task summaries
- );
+ getAuthToken({
+ website: 'http://public.businesslearninginc.com', // the taiga website to gather tasks
+ project: 'admin-sorce-migration', // the taiga project slug (not project name)
+ authToken: '', // session authentication token (derived)
+ projectID: '', // project ID (derived)
+ projectName: '', // project name (derived)
+ adminUsername: $scope.dlgModel.username, // project user with admin permissions (to access task details)
+ adminPassword: $scope.dlgModel.password, // project user password
+ startDate: startDate, // user story start date range
+ endDate: endDate, // user story end date range
+ showIncompleteTasks: $scope.dlgModel.radio, // whether to include incomplete tasks in results
+ users: users, // list of users to gather task summaries
+ userName: '', // user name (derived)
+ userCount: 0, // count of users passed in (derived)
+ userID: '' // user ID of current user (derived)
+ });
});
});
-angular.module('ui.bootstrap.demo').controller('ModalInstanceCtrl', function($scope, $modalInstance, checkModel, dlgModel) {
+app.controller('ModalInstanceCtrl', function($scope, $modalInstance, checkModel, dlgModel) {
$scope.checkModel = checkModel;
$scope.dlgModel = dlgModel;
@@ -81,6 +187,7 @@ angular.module('ui.bootstrap.demo').controller('ModalInstanceCtrl', function($sc
$scope.reset = function() {
$scope.dlgModel.username = "";
$scope.dlgModel.password = "";
+ $scope.dlgModel.radio = true;
$scope.checkModel.duane = false;
$scope.checkModel.troje = false;
diff --git a/taiga_tasks/remote/taiga_tasks.html b/taiga_tasks/remote/taiga_tasks.html
index c448fad..e975f3e 100644
--- a/taiga_tasks/remote/taiga_tasks.html
+++ b/taiga_tasks/remote/taiga_tasks.html
@@ -15,22 +15,31 @@
-->
-
+
+
-
-
-
-
-
+
+
+
+
+
+
-
+