diff --git a/app/index.html b/app/index.html index 5769bbc4..63e7c09e 100644 --- a/app/index.html +++ b/app/index.html @@ -11,6 +11,8 @@ + + @@ -38,7 +40,9 @@ + + @@ -49,6 +53,9 @@ + + + + + + + + diff --git a/app/scripts/app.js b/app/scripts/app.js index cefab8df..3799da8b 100644 --- a/app/scripts/app.js +++ b/app/scripts/app.js @@ -16,9 +16,11 @@ angular 'ngRoute', 'ngSanitize', 'ngTouch', - 'ng-polymer-elements' + 'ng-polymer-elements', + 'oauth', + 'angularFileUpload' ]) - .config(function ($routeProvider) { + .config(['$routeProvider', '$locationProvider', function ($routeProvider, $locationProvider) { $routeProvider .when('/', { templateUrl: 'views/main.html', @@ -31,4 +33,6 @@ angular .otherwise({ redirectTo: '/' }); - }); + + $locationProvider.html5Mode(true).hashPrefix('!'); + }]); diff --git a/app/scripts/controllers/create.js b/app/scripts/controllers/create.js new file mode 100644 index 00000000..4bb39bc1 --- /dev/null +++ b/app/scripts/controllers/create.js @@ -0,0 +1,102 @@ +'use strict'; + +/** + * @ngdoc function + * @name requirementsBazaarWebFrontendApp.controller:CreateCtrl + * @description + * # CreateCtrl + * Controller of the requirementsBazaarWebFrontendApp + */ +angular.module('requirementsBazaarWebFrontendApp') + .controller('CreateCtrl', function ($scope, reqBazService, UtilityService, $upload) { + + $scope.showCreateDiv = false; + $scope.newName = ''; + $scope.newDesc = ''; + + $scope.createAttachments = []; + + //Creating a requirement + $scope.submitReq = function(){ + if(!UtilityService.isEmpty($scope.newName,'Choose requirement name') && !UtilityService.isEmpty($scope.newDesc,'Choose requirement description')) { + if($scope.createAttachments.length !== 0){ + //TODO save the attachments + $scope.createAttachments = []; + UtilityService.showFeedback('Warning: Attachments were not included !'); + } + console.log('submit requirement'); + var requirement = {title: $scope.newName, description: $scope.newDesc, projectId: $scope.activeProject.id, leadDeveloperId: 1, creatorId: 1}; + reqBazService.createRequirement($scope.activeProject.id, $scope.activeComponent.id, requirement) + .success(function (message) { + console.log(message); + if (message.hasOwnProperty('errorCode')) { + UtilityService.showFeedback('Warning: Requirement was not created !'); + } else { + //Add missing values to the newly created requirement + requirement.id = message.id; + requirement.creator = {firstName: 'loading'}; + requirement.leadDeveloper = {firstName: 'loading'}; + requirement.followers = []; + requirement.developers = []; + requirement.contributors = []; + requirement.attachments = []; + requirement.components = []; + + //Add the requirement to the first position + $scope.requirements.splice(0, 0, requirement); + $scope.clearSubmit(); + } + }) + .error(function (error) { + //This error only catches unknown server errors, usual errorCodes are sent with success message + console.log(error); + UtilityService.showFeedback('Warning: Requirement was not created !'); + }); + } + }; + + + $scope.submitProject = function(){ + if(!UtilityService.isEmpty($scope.newName,'Choose project name') && !UtilityService.isEmpty($scope.newDesc, 'Choose project description')){ + console.log('submit new project'); + var project = {description: $scope.newDesc, name: $scope.newName, visibility: 'PUBLIC', leaderId: 1}; + reqBazService.createProject(project) + .success(function (message) { + console.log(message); + if(message.hasOwnProperty('errorCode')){ + UtilityService.showFeedback('Warning: Project was not created !'); + }else { + UtilityService.showFeedback('Project was created'); + + //The project is added to be the first element and will be active + project.id = message.id; + $scope.activeProject = project; + $scope.projects.splice(0, 0, $scope.activeProject); + $scope.selectProj($scope.activeProject); + $scope.clearSubmit(); + } + }) + .error(function (error) { + console.log(error); + UtilityService.showFeedback('Warning: Project was not created !'); + }); + } + }; + + $scope.clearSubmit = function(){ + $scope.newName = ''; + $scope.newDesc = ''; + $scope.showCreateDiv = false; + }; + + $scope.newAttachments = function(files){ + if(files[0].type.indexOf('image/') > -1){ + $scope.createAttachments.push({'file':files[0],'URL':URL.createObjectURL(files[0])}); + } + if(files[0].type.indexOf('application/pdf') > -1 || files[0].type.indexOf('video/') > -1){ + console.log('is pdf or video'); + $scope.createAttachments.push({'file':files[0],'URL':null}); + } + console.log($scope.createAttachments); + }; + }); diff --git a/app/scripts/controllers/createComponent.js b/app/scripts/controllers/createComponent.js new file mode 100644 index 00000000..87fd31a0 --- /dev/null +++ b/app/scripts/controllers/createComponent.js @@ -0,0 +1,49 @@ +'use strict'; + +/** + * @ngdoc function + * @name requirementsBazaarWebFrontendApp.controller:CreateComponentCtrl + * @description + * # CreateComponentCtrl + * Controller of the requirementsBazaarWebFrontendApp + */ +angular.module('requirementsBazaarWebFrontendApp') + .controller('CreateComponentCtrl', function ($scope, reqBazService, UtilityService, $upload) { + + //Creates a new component + $scope.showCreateCompDiv = false; + $scope.newCompName = ''; + $scope.newCompDesc = ''; + $scope.submitNewComponent = function(){ + if(!UtilityService.isEmpty($scope.newCompName,'Provide a name for the component')) { + console.log('submit new component'); + var component = {description: $scope.newCompDesc, name: $scope.newCompName, leaderId: 1, projectId: $scope.activeProject.id}; + reqBazService.createComponent($scope.activeProject.id,component) + .success(function (message) { + console.log(message); + if(message.hasOwnProperty('errorCode')){ + UtilityService.showFeedback('Warning: Component was not created !'); + }else { + UtilityService.showFeedback('Component was created'); + component.id = message.id; + + //The component is added to be the first element and will be active + $scope.activeComponent = component; + $scope.components.splice(0, 0, $scope.activeComponent); + $scope.selectComp($scope.activeComponent); + $scope.clearComponentSubmit(); + } + }) + .error(function (error) { + console.log(error); + UtilityService.showFeedback('Warning: Component was not created !'); + }); + } + }; + + $scope.clearComponentSubmit = function(){ + $scope.newCompName = ''; + $scope.newCompDesc = ''; + $scope.showCreateCompDiv = false; + }; + }); diff --git a/app/scripts/controllers/main.js b/app/scripts/controllers/main.js index 8b8c1b41..d18a0e48 100644 --- a/app/scripts/controllers/main.js +++ b/app/scripts/controllers/main.js @@ -8,12 +8,12 @@ * Controller of the requirementsBazaarWebFrontendApp */ angular.module('requirementsBazaarWebFrontendApp') - .controller('MainCtrl', function ($scope, reqBazService) { + .controller('MainCtrl', function ($scope, reqBazService, UtilityService, $upload) { $scope.projects = null; $scope.components = null; $scope.requirements = null; - $scope.activeUser = {id : '1', firstname : 'Kristjan', lastname : 'Liiva', email : 'liiva@web.com', admin : 'true', Las2PeerId :'000', username : 'KristjanLiiva'}; + $scope.activeUser = {id : '2', firstname : 'Max2', lastname : 'Mustermann2', email : 'Max@Mustermann2.de', admin : 'true', Las2PeerId :'2'}; $scope.projectLeader = null; $scope.componentLeader = null; @@ -21,209 +21,174 @@ angular.module('requirementsBazaarWebFrontendApp') $scope.activeProject = null; $scope.activeComponent = null; - $scope.warningText = 'Confirm deletion !'; - $scope.warningVisible = false; + //In case loading requirements/components fails, show a reload button + $scope.reloadRequirements = false; + $scope.reloadComponents = false; - //init functions that need to be run when the user enters the page - function getProjects(){ + /* + * Loads projects and then components ... + * Called: only when the page loads + * */ + (function(){ reqBazService.getProjects() .success(function (projs) { $scope.projects = projs; - $scope.activeProject = $scope.projects[0]; - $scope.selectProj($scope.activeProject); - + if($scope.projects.length !== 0){ + $scope.activeProject = $scope.projects[0]; + $scope.selectProj($scope.activeProject); + }else{ + //TODO somehow gracefully handle the fact that there are no projects + } }) - .error(function (error) { - $scope.status = 'Unable to load customer data: ' + error.message; + .error(function () { + UtilityService.showFeedback('Could not load projects, please reload !'); }); - } + })(); - //Is called when the user selects a new project + /* + * Switches the active project and loads components belonging to it + * Called: User selects a new project or reloads components + * */ $scope.selectProj = function (project) { + $scope.reloadComponents = false; $scope.activeProject = project; - reqBazService.getComponents($scope.activeProject.id,'0','30') .success(function (comps) { $scope.components = comps; $scope.activeComponent = $scope.components[0]; - console.log($scope.activeComponent); $scope.selectComp($scope.activeComponent); }) - .error(function (error) { - $scope.status = 'ERROR: ' + error.message; + .error(function () { + //Null the lists, otherwise user will see wrong components/requirements + $scope.components = null; + $scope.activeComponent = null; + $scope.requirements = null; + UtilityService.showFeedback('Could not load components'); + + //Show the reload requirements button + $scope.reloadComponents = true; }); }; - //Is called when the user has selected a different component + /* + * Switches the active component and loads requirements belonging to it + * Called: User selects a new component/project or reloads requirements + * */ $scope.selectComp = function (component) { + $scope.reloadRequirements = false; $scope.activeComponent = component; getUser($scope.activeComponent.leaderId,'component'); - console.log('get requirements for projectID: '+$scope.activeProject.id+' and componentID: '+$scope.activeComponent.id); + + //Load the requirements reqBazService.getRequirementsByComponent($scope.activeProject.id,$scope.activeComponent.id) .success(function (reqs) { $scope.requirements = reqs; - console.log($scope.requirements); + if($scope.requirements.length === 0){ + UtilityService.showFeedback( 'This component has no requirements, feel free to create'); + }else{ + //Show the requirements + for(var i = 0; i<$scope.requirements.length;i++){ + //This adds the missing attributes to the requirements + $scope.requirements[i].creator = {firstName : 'loading'}; + $scope.requirements[i].leadDeveloper = {firstName : 'loading'}; + $scope.requirements[i].followers = []; + $scope.requirements[i].developers = []; + $scope.requirements[i].contributors = []; + $scope.requirements[i].attachments = []; + $scope.requirements[i].components = []; + + $scope.requirements[i].comments = []; + } + } }) - .error(function (error) { - $scope.status = 'ERROR: ' + error.message; + .error(function () { + //Null the list, otherwise user will see wrong requirements + $scope.requirements = null; + UtilityService.showFeedback('Could not load requirements'); + + //Show the reload requirements button + $scope.reloadRequirements = true; }); }; - //Queries for users + /* + * Loads user information + * Called: automatically, when a component/requirement etc is shown + * */ function getUser(id,purpose){ reqBazService.getUser(id) .success(function (user) { if(purpose === 'component'){ $scope.componentLeader = user; - }else if(purpose === 'project'){ + } + if(purpose === 'project'){ $scope.projectLeader = user; - }else{ - } }) - .error(function (error) { - console.log(error.message); - $scope.status = 'ERROR: ' + error.message; + .error(function () { + if(purpose === 'component'){ + $scope.componentLeader = null; + } + if(purpose === 'project'){ + $scope.projectLeader = null; + } + UtilityService.showFeedback('Could not load user for: '+purpose); }); } - //Call the init functions - getProjects(); - - $scope.toggle = function(clickEvent,index) { - console.log(index); - var collapse = clickEvent.target.nextElementSibling; - if(collapse.getAttribute('data-visible') === 'false'){ - console.log('opened requirement'); - collapse.setAttribute('data-visible', 'true'); - //Get all the missing pieces of information, like leader, follower, votes + /* + * Everything related to creating or deleting a project + * + * */ - }else{ - collapse.setAttribute('data-visible', 'false'); - } - - //toggle visibility of the requirement - collapse.toggle(); - }; - - $scope.toggleAttachments = function(clickEvent) { - console.log('toggle attachments'); + $scope.initDeleteProject = function(){ + document.getElementById('confirmDeleteProject').toggle(); }; - $scope.toggleComments = function(clickEvent) { - console.log('toggle comments'); + $scope.deleteProject = function(){ + console.log('delete project confirmed'); + //TODO delete the project + UtilityService.showFeedback('This feature is currently under discussion'); }; - //Creates a new component - $scope.showCreateCompDiv = false; - $scope.newCompName = ''; - $scope.newCompDesc = ''; - $scope.submitNewComponent = function(){ - if($scope.newCompName !== ''){ - console.log('submit new component'); - //TODO leaderId is not used, as there is no user management yet - var component = {description: $scope.newCompDesc, name: $scope.newCompName, leaderId: 1, projectId: $scope.activeProject.id}; - reqBazService.createComponent($scope.activeProject.id,component) - .success(function (message) { - console.log(message); - //TODO add the new component to the $scope.component and then set everything to default - $scope.clearComponentSubmit(); - }) - .error(function (error) { - console.log(error.message); - alert('Something went wrong, please try again'); - }); - }else{ - console.log('Input field empty'); - //TODO Show toast - } - }; - $scope.clearComponentSubmit = function(){ - $scope.newCompName = ''; - $scope.newCompDesc = ''; - $scope.showCreateCompDiv = false; - }; + /* + * Everything related to creating or deleting a new component + * + * */ $scope.initDeleteComponent = function () { - $scope.warningText = 'Confirm deleting the component !'; - $scope.warningVisible = true; - }; - $scope.cancelDeleteComponent = function(){ - $scope.warningText = 'Confirm deletion !'; - $scope.warningVisible = false; + document.getElementById('confirmDeleteComponent').toggle(); }; $scope.deleteComponent = function(){ - $scope.warningText = 'Confirm deletion !'; - $scope.warningVisible = false; reqBazService.deleteComponent($scope.activeProject.id,$scope.activeComponent.id) .success(function (message) { console.log(message); - for(var i = 0; i<$scope.components.length;i++){ - if($scope.components[i].id === $scope.activeComponent.id){ - $scope.components.splice(i, 1); - break; + if(message.success !== 'true'){ + UtilityService.showFeedback('Warning: Component was not deleted !'); + }else { + for (var i = 0; i < $scope.components.length; i++) { + if ($scope.components[i].id === $scope.activeComponent.id) { + $scope.components.splice(i, 1); + break; + } } - } - $scope.activeComponent = null; - if($scope.components !== null){ - $scope.activeComponent = $scope.components[0]; + + //set a new active component + $scope.activeComponent = null; + if ($scope.components !== null) { + $scope.activeComponent = $scope.components[0]; + } + + UtilityService.showFeedback('Component deleted'); } }) .error(function (error) { - console.log(error.message); - alert('Could not delete, please try again'); + console.log(error); + UtilityService.showFeedback('Warning: Component was not deleted !'); }); }; - //Creating a requirement - $scope.showCreateReqDiv = false; - $scope.newReqName = ''; - $scope.newReqDesc = ''; - $scope.submitNewReq = function(){ - if($scope.newReqName !== '' && $scope.newReqDesc !== ''){ - console.log('submit requirement'); - var requirement = {title: $scope.newReqName, description: $scope.newReqDesc, projectId: $scope.activeProject.id, leadDeveloperId : 1, creatorId : 1}; - - console.log($scope.activeProject.id); - console.log($scope.activeComponent.id); - console.log(requirement); - reqBazService.createRequirement($scope.activeProject.id,$scope.activeComponent.id,requirement) - .success(function (message) { - console.log(message); - }) - .error(function (error) { - console.log(error.message); - }); - - $scope.showCreateReqDiv = false; - //this.createRequirement = function(projectId, componentId, requirement){ - // var reqUrl = url + 'projects/' + projectId + '/components/' + componentId + '/requirements'; - // return $http.post(reqUrl, requirement); - //}; - - }else{ - console.log('Input field empty'); - //TODO Show toast - } - }; - $scope.clearReqSubmit = function(){ - $scope.newReqName = ''; - $scope.newReqDesc = ''; - $scope.showCreateReqDiv = false; - }; - - - - - $scope.signOut = function(){ - window.alert('TODO sign out'); - }; - - $scope.editProfile = function(){ - window.alert('TODO'); - }; - }); diff --git a/app/scripts/controllers/requirement.js b/app/scripts/controllers/requirement.js new file mode 100644 index 00000000..ab82f6f0 --- /dev/null +++ b/app/scripts/controllers/requirement.js @@ -0,0 +1,244 @@ +'use strict'; + +/** + * @ngdoc function + * @name requirementsBazaarWebFrontendApp.controller:RequirementCtrl + * @description + * # RequirementCtrl + * Controller of the requirementsBazaarWebFrontendApp + */ +angular.module('requirementsBazaarWebFrontendApp') + .controller('RequirementCtrl', function ($scope, reqBazService, UtilityService, $upload) { + + $scope.attachments = []; + + /* + * Currently only images, videos and pdfs are accepted as attachments + * Called: when the user has selected a file + * */ + $scope.fileSelected = function (files) { + if(files[0].type.indexOf('image/') > -1){ + $scope.attachments.push({'file':files[0],'URL':URL.createObjectURL(files[0])}); + } + if(files[0].type.indexOf('application/pdf') > -1 || files[0].type.indexOf('video/') > -1){ + console.log('is pdf or video'); + $scope.attachments.push({'file':files[0],'URL':null}); + } + console.log($scope.attachments); + }; + + + //$scope.upload = $upload.upload({ + // url: 'server/upload/url', + // data: {myObj: $scope.myModelObj}, + // file: $scope.files + //}).progress(function(evt) { + // console.log('progress: ' + parseInt(100.0 * evt.loaded / evt.total) + '% file :'+ evt.config.file.name); + //}).success(function(data, status, headers, config) { + // console.log('file ' + config.file.name + 'is uploaded successfully. Response: ' + data); + //}); + + + + /* + * After the user has finished editing + * Called: by the user, by clicking on submit requirement + * */ + $scope.updateRequirement = function(req){ + console.log('save changes'); + console.log('text : '+req.description); + if($scope.attachments !== null){ + console.log('with attachments:'); + } + + console.log($scope.attachments); + UtilityService.showFeedback('Warning: Not implemented'); + + //TODO update req text + //TODO save all the attachments that did not exist before? + + //var url = 'http://localhost:8080/bazaar/'; + //var attachmentUrl = url + 'projects/' + 0 + '/components/' + 0 + '/requirements/' + 0 + '/attachments'; + //attachmentUrl+= '?attachmentType=F'; + // + //$scope.upload = $upload.upload({ + // url: attachmentUrl, + // data: {myObj: $scope.myModelObj}, + // file: $scope.files + //}).progress(function(evt) { + // console.log('progress: ' + parseInt(100.0 * evt.loaded / evt.total) + '% file :'+ evt.config.file.name); + //}).success(function(data, status, headers, config) { + // console.log('file ' + config.file.name + 'is uploaded successfully. Response: ' + data); + //}); + + + //this.createAttachment = function(attachmentType, attachment){ + // var attachmentUrl = url + 'projects/' + 0 + '/components/' + 0 + '/requirements/' + 0 + '/attachments'; + // + // attachmentUrl+= '?attachmentType' + attachmentType; + // + // return $http.post(attachmentUrl, attachment); + //}; + + }; + + + + /* + * Toggles the visibility of a requirements + * Called: user clicks on the requirement + * */ + $scope.toggleRequirement = function(clickEvent,req) { + var collapse = clickEvent.target.parentNode.nextElementSibling; + if(collapse.getAttribute('data-visible') === 'false'){ + console.log('opened requirement'); + collapse.setAttribute('data-visible', 'true'); + //Get all the missing pieces of information, like leader, follower, votes + reqBazService.getRequirement(req.id) + .success(function (requirement) { + console.log(requirement); + req.creator = requirement.creator; + req.attachments = requirement.attachments; + req.components = requirement.components; + req.leadDeveloper = requirement.leadDeveloper; + req.followers = requirement.followers; + req.developers = requirement.developers; + req.contributors = requirement.contributors; + + //Load comments + getComments(req); + }) + .error(function () { + UtilityService.showFeedback('Warning: the requirement was not loaded !'); + }); + }else{ + collapse.setAttribute('data-visible', 'false'); + } + + //toggle visibility of the requirement + collapse.toggle(); + }; + + + var getComments = function(req){ + reqBazService.getComments(req.id,0,30) + .success(function (comments) { + req.comments = comments; + }) + .error(function (error) { + //This error only catches unknown server errors, usual errorCodes are sent with success message + console.log(error); + UtilityService.showFeedback('Warning: Could not get comments'); + }); + }; + + + /* + * Submits a comment, time of the post is initially approximate + * Called: by the user + * */ + $scope.submitComment = function(text,req){ + if(!UtilityService.isEmpty(text,'Comment cannot be empty')){ + console.log('post comment: '+text); + // user 1 is the current anon user + var comment = {requirementId: req.id, message: text, creatorId: 1}; + + reqBazService.createComment(req.id,comment) + .success(function (message) { + console.log(message); + if(message.hasOwnProperty('errorCode')){ + UtilityService.showFeedback('Warning: Comment was not submitted !'); + }else{ + comment.Id = message.id; + //Instead of making a new server call, just approximate + comment.creationTime = Date(); + req.comments.splice(0, 0, comment); + } + }) + .error(function (error) { + //This error only catches unknown server errors, usual errorCodes are sent with success message + console.log(error); + UtilityService.showFeedback('Warning: Comment was not submitted !'); + }); + } + }; + + /* + * Comment is deleted without further confirmation + * Called: by the user + * */ + $scope.deleteComment = function(id,req){ + reqBazService.deleteComment(id) + .success(function (message) { + console.log(message); + if(message.success !== 'true'){ + UtilityService.showFeedback('Warning: Comment was not deleted !'); + }else{ + // Delete the removed requirement from the list + for(var i = 0; i \ No newline at end of file diff --git a/app/views/main.html b/app/views/main.html index f06ebcb4..e159f4a3 100644 --- a/app/views/main.html +++ b/app/views/main.html @@ -11,129 +11,172 @@ + - -
+ +

Here will be notifications

- -
+ +

{{activeUser.firstname}} {{activeUser.lastname}}

{{activeUser.email}}

Is admin : {{activeUser.admin}}

-
- Edit - Sign Out -
+ + + + + +
-