This is an automated email from the git hooks/post-receive script. New commit to branch develop in repository coselmar. See http://git.codelutin.com/coselmar.git commit 408c5cd151ff1198dd2987bdcf8538d9377f51fe Author: Yannick Martel <martel@©odelutin.com> Date: Thu Jan 7 16:49:23 2016 +0100 fixes #7867 add links management in project page --- .../src/main/xmi/coselmar-model.zargo | Bin 10967 -> 10955 bytes .../services/CoselmarRestApplicationListener.java | 4 +- .../coselmar/services/v1/QuestionsWebService.java | 22 +++++- coselmar-ui/src/main/webapp/i18n/en.js | 11 ++- coselmar-ui/src/main/webapp/i18n/fr.js | 11 ++- .../src/main/webapp/js/coselmar-controllers.js | 69 +++++++++++++++++- .../src/main/webapp/views/links/modalLinkEdit.html | 78 +++++++++++++++++++++ .../main/webapp/views/questions/editquestion.html | 42 ++++++++++- .../main/webapp/views/questions/viewquestion.html | 16 +++++ 9 files changed, 245 insertions(+), 8 deletions(-) diff --git a/coselmar-persistence/src/main/xmi/coselmar-model.zargo b/coselmar-persistence/src/main/xmi/coselmar-model.zargo index 38acbde..1f35409 100644 Binary files a/coselmar-persistence/src/main/xmi/coselmar-model.zargo and b/coselmar-persistence/src/main/xmi/coselmar-model.zargo differ diff --git a/coselmar-rest/src/main/java/fr/ifremer/coselmar/services/CoselmarRestApplicationListener.java b/coselmar-rest/src/main/java/fr/ifremer/coselmar/services/CoselmarRestApplicationListener.java index d0df76f..7c02356 100644 --- a/coselmar-rest/src/main/java/fr/ifremer/coselmar/services/CoselmarRestApplicationListener.java +++ b/coselmar-rest/src/main/java/fr/ifremer/coselmar/services/CoselmarRestApplicationListener.java @@ -30,6 +30,7 @@ import java.util.Set; import com.google.common.collect.Sets; import fr.ifremer.coselmar.beans.DocumentBean; import fr.ifremer.coselmar.beans.DocumentSearchBean; +import fr.ifremer.coselmar.beans.LinkBean; import fr.ifremer.coselmar.beans.QuestionBean; import fr.ifremer.coselmar.beans.QuestionSearchBean; import fr.ifremer.coselmar.beans.QuestionSearchExample; @@ -56,7 +57,8 @@ public class CoselmarRestApplicationListener implements WebMotionServerListener UserSearchBean.class, QuestionSearchBean.class, DocumentSearchBean.class, - QuestionSearchExample.class + QuestionSearchExample.class, + LinkBean.class ); @Override diff --git a/coselmar-rest/src/main/java/fr/ifremer/coselmar/services/v1/QuestionsWebService.java b/coselmar-rest/src/main/java/fr/ifremer/coselmar/services/v1/QuestionsWebService.java index 8305152..b390f49 100644 --- a/coselmar-rest/src/main/java/fr/ifremer/coselmar/services/v1/QuestionsWebService.java +++ b/coselmar-rest/src/main/java/fr/ifremer/coselmar/services/v1/QuestionsWebService.java @@ -227,13 +227,21 @@ public class QuestionsWebService extends CoselmarWebServiceSupport { Link linkEntity = null; String linkId = link.getId(); if (StringUtils.isNotBlank(linkId)) { - linkEntity = getPersistenceContext().getLinkDao().forTopiaIdEquals(getFullIdFromShort(Link.class, linkId)).findFirstOrNull(); + linkEntity = getPersistenceContext().getLinkDao().forTopiaIdEquals(getFullIdFromShort(Link.class, linkId)).findUniqueOrNull(); } if (linkEntity == null) { linkEntity = new LinkImpl(); } linkEntity.setName(link.getName()); linkEntity.setUrl(link.getUrl()); + + if (StringUtils.isNotBlank(linkEntity.getTopiaId())) { + getPersistenceContext().getLinkDao().update(linkEntity); + } else { + getPersistenceContext().getLinkDao().create(linkEntity); + } + + questionEntity.addLinks(linkEntity); } } @@ -781,18 +789,28 @@ public class QuestionsWebService extends CoselmarWebServiceSupport { // Links Set<LinkBean> links = question.getLinks(); + questionEntity.clearLinks(); if (links != null && !links.isEmpty()) { for (LinkBean link : links) { Link linkEntity = null; String linkId = link.getId(); if (StringUtils.isNotBlank(linkId)) { - linkEntity = getPersistenceContext().getLinkDao().forTopiaIdEquals(getFullIdFromShort(Link.class, linkId)).findFirstOrNull(); + String linkFullId = getFullIdFromShort(Link.class, linkId); + linkEntity = getPersistenceContext().getLinkDao().forTopiaIdEquals(linkFullId).findUniqueOrNull(); } if (linkEntity == null) { linkEntity = new LinkImpl(); } linkEntity.setName(link.getName()); linkEntity.setUrl(link.getUrl()); + + if (StringUtils.isNotBlank(linkEntity.getTopiaId())) { + getPersistenceContext().getLinkDao().update(linkEntity); + } else { + getPersistenceContext().getLinkDao().create(linkEntity); + } + + questionEntity.addLinks(linkEntity); } } diff --git a/coselmar-ui/src/main/webapp/i18n/en.js b/coselmar-ui/src/main/webapp/i18n/en.js index e94e64e..9a6126a 100644 --- a/coselmar-ui/src/main/webapp/i18n/en.js +++ b/coselmar-ui/src/main/webapp/i18n/en.js @@ -158,7 +158,8 @@ var translateEN = { "question.metadata.parentsPhrase" : "Produced or inspired by", "question.metadata.childrenPhrase" : "Has produced or inspired", "question.metadata.participants" : "Participants", -"question.metadata.links" : "To get more", +"question.metadata.links" : "Associated Links", +"question.metadata.links.display" : "Go further", "question.metadata.submitBefore" : "Submit before", "question.metadata.submitAfter" : "Submit after", @@ -201,6 +202,14 @@ var translateEN = { "question.message.info.themes" : "Themes enable to classify project and make search easier. Each input theme should be validated with button \"Add\".", "question.message.info.contributors" : "Contributors are experts who have been experts on the project before.", +// Links + +"link.metadata.url" : "URL", +"link.metadata.name" : "Display name", + +"link.create.title" : "Add a link", +"link.update.title" : "Update link", + //Users part "user.list.title" : "All users", diff --git a/coselmar-ui/src/main/webapp/i18n/fr.js b/coselmar-ui/src/main/webapp/i18n/fr.js index d242934..c88beb9 100644 --- a/coselmar-ui/src/main/webapp/i18n/fr.js +++ b/coselmar-ui/src/main/webapp/i18n/fr.js @@ -158,7 +158,8 @@ var translateFR = { "question.metadata.parentsPhrase" : "Provoqué ou inspiré par", "question.metadata.childrenPhrase" : "A provoqué ou inspiré", "question.metadata.participants" : "Participants", -"question.metadata.links" : "Pour aller plus loin", +"question.metadata.links" : "Liens associés", +"question.metadata.links.display" : "Pour aller plus loin", "question.metadata.submitBefore" : "Soumis avant le", "question.metadata.submitAfter" : "Soumis après le", @@ -201,6 +202,14 @@ var translateFR = { "question.message.info.themes" : "Les thèmes permettent de classifier le projet et faciliter sa recherche. Chaque thème saisi doit être validé avec le bouton \"Ajouter\".", "question.message.info.contributors" : "Les contributeurs sont des experts ayant été affectés au projet et qui ne le sont plus.", +// Links + +"link.metadata.url" : "Adresse web", +"link.metadata.name" : "Nom", + +"link.create.title" : "Ajouter un lien", +"link.update.title" : "Mettre à jour le lien", + //Users part "user.list.title" : "Liste des utilisateurs", diff --git a/coselmar-ui/src/main/webapp/js/coselmar-controllers.js b/coselmar-ui/src/main/webapp/js/coselmar-controllers.js index 5ef7151..16fb2e7 100644 --- a/coselmar-ui/src/main/webapp/js/coselmar-controllers.js +++ b/coselmar-ui/src/main/webapp/js/coselmar-controllers.js @@ -1023,7 +1023,8 @@ coselmarControllers.controller("QuestionCtrl", ['$scope', '$route', '$routeParam $scope.question = {'privacy' : 'PUBLIC', 'themes' : [], 'participants' : [], 'externalExperts' : [], - 'clients' : [], 'relatedDocuments': [], 'newRelatedDocuments' : [] }; + 'clients' : [], 'relatedDocuments': [], 'newRelatedDocuments' : [], + 'links' : []}; $scope.existing = {'types' : [], 'themes' : []}; // Preload exiting types and themes @@ -1154,6 +1155,10 @@ coselmarControllers.controller("QuestionCtrl", ['$scope', '$route', '$routeParam bindUsers($scope.question.supervisors, $scope.supervisorsIndex); } + if(!question.links) { + $scope.question.links = []; + } + }, errorService.defaultFailOnCall); }; @@ -1409,6 +1414,46 @@ coselmarControllers.controller("QuestionCtrl", ['$scope', '$route', '$routeParam return isClient; }; + $scope.modalEditLink = function (link) { + + var modalInstance = $uibModal.open({ + templateUrl: 'views/links/modalLinkEdit.html', + controller: 'ModalEditLinkCtrl', + size: 'lg', + resolve : { + currentLink : function() { + if (angular.isDefined(link)) { + return link; + } else { + return { name : "", url: ""}; + } + } + } + }); + + modalInstance.result.then(function (link) { + console.log("result is"); + console.log(link); + var already = false; + for (var i = 0; i < $scope.question.links.length; i++) { + if ($scope.question.links[i].id == link.id) { + already = true; + $scope.question.links[i] = link; + } + } + if (!already) { + $scope.question.links.push(link); + } + }); + }; + + $scope.removeLink = function(link) { + var position = $scope.question.links.indexOf(link); + if (link && position != -1) { + $scope.question.links.splice(link, 1); + } + }; + }]); coselmarControllers.controller('ModalSearchDocumentsCtrl', function ($scope, $uibModalInstance, documentService, errorService) { @@ -1531,6 +1576,28 @@ coselmarControllers.controller('ModalCreateDocumentsCtrl', function ($scope, $ui }); +coselmarControllers.controller('ModalEditLinkCtrl', function ($scope, $uibModalInstance, currentLink) { + + $scope.link = currentLink; + console.log(currentLink); + $scope.invalidUrl = false; + + $scope.create = function () { + + if ($scope.link.url === "") { + $scope.invalidUrl = true; + } else { + $uibModalInstance.close($scope.link); + } + + }; + + $scope.cancel = function () { + $uibModalInstance.dismiss('cancel'); + }; + +}); + ///////////////////////////////////////////////// /////////// Referential Part ////////////////// diff --git a/coselmar-ui/src/main/webapp/views/links/modalLinkEdit.html b/coselmar-ui/src/main/webapp/views/links/modalLinkEdit.html new file mode 100644 index 0000000..8760f8f --- /dev/null +++ b/coselmar-ui/src/main/webapp/views/links/modalLinkEdit.html @@ -0,0 +1,78 @@ +<!-- + #%L + Coselmar :: UI + $Id:$ + $HeadURL:$ + %% + Copyright (C) 2014 Ifremer, Code Lutin + %% + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as + published by the Free Software Foundation, either version 3 of the + License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public + License along with this program. If not, see + <http://www.gnu.org/licenses/gpl-3.0.html>. + #L% + --> +<div xmlns="http://www.w3.org/1999/html"> + <div class="modal-title"> + <h2 class="paddingLeft20" ng-if="link.id">{{ 'link.update.title' | translate }}</h2> + <h2 class="paddingLeft20" ng-if="!link.id">{{ 'link.create.title' | translate }}</h2> + <span translate="common.message.mandatoryFieldsInfo" class="marginLeft20"></span> + </div> + + <form class="form-horizontal" name="linkForm" role="form" ng-submit="create()"> + + <div class="modal-body"> + + <div class="form-group row"> + + <div class="" + ng-class="{'has-error' : linkForm.linkUrl.$invalid && !linkForm.linkUrl.$pristine}"> + <label class="col-md-4 control-label" for="linkUrl"> + {{ 'link.metadata.url' | translate }} * + </label> + + <div class="col-md-8"> + <input type="text" class="form-control" id="linkUrl" + placeholder="Link Name" + ng-model="link.url" required /> + + <p ng-show="linkForm.linkUrl.$invalid && !linkForm.linkUrl.$pristine" + class="help-block">{{ 'link.message.requiredUrl' | translate }}</p> + </div> + </div> + </div> + + <div class="form-group row"> + <div class=""> + <label class="col-md-4 control-label" for="name"> + {{ 'link.metadata.name' | translate }} + </label> + + <div class="col-md-8"> + <input type="text" class="form-control" id="name" + placeholder="Name" + ng-model="link.name"/> + </div> + </div> + + </div> + </div> + + <div class="modal-footer"> + <button class="btn btn-action btn-disable" ng-click="cancel()">{{ 'common.button.cancel' | translate }}</button> + <input type="submit" value="{{ 'common.button.validate' | translate}}" class="btn btn-action btn-success float-right" + ng-disabled="linkForm.$invalid" /> + </div> + + </form> + +</div> \ No newline at end of file diff --git a/coselmar-ui/src/main/webapp/views/questions/editquestion.html b/coselmar-ui/src/main/webapp/views/questions/editquestion.html index 1621f49..a035b03 100644 --- a/coselmar-ui/src/main/webapp/views/questions/editquestion.html +++ b/coselmar-ui/src/main/webapp/views/questions/editquestion.html @@ -256,7 +256,7 @@ </ui-select-match> <ui-select-choices - repeat="expert in users.participants track by expert.id | propsFilter: {name: $select.search, firstName: $select.search, organization: $select.search}" + repeat="expert in ( users.participants | propsFilter: {name: $select.search, firstName: $select.search, organization: $select.search} ) track by expert.id " refresh="refreshExperts($select.search)" refresh-delay="500"> {{expert.firstName}} {{expert.name}} ({{expert.organization}}) @@ -329,7 +329,7 @@ </ui-select-match> <ui-select-choices - repeat="expert in users.supervisors track by expert.id | propsFilter: {name: $select.search, firstName: $select.search, organization: $select.search}" + repeat="expert in ( users.supervisors | propsFilter: {name: $select.search, firstName: $select.search, organization: $select.search} ) track by expert.id" refresh="refreshSupervisors($select.search)" refresh-delay="500"> {{expert.firstName}} {{expert.name}} ({{expert.organization}}) @@ -344,3 +344,41 @@ <!-- End Line with External Experts and Supervisor --> + <!-- Line with Related Links --> + + <div class="form-group" > + + + <label class="col-md-2 control-label">{{ 'question.metadata.links' | translate }}</label> + + <div class="col-md-10"> + <table class="table table-bordered table-condensed"> + <thead> + <tr> + <th>{{ 'link.metadata.name' | translate }}</th> + <th>{{ 'link.metadata.url' | translate }}</th> + <th> + <a class="btn fa fa-plus" title="Add new link" + ng-click="modalEditLink()"/> + </th> + </tr> + </thead> + <tbody> + <tr ng-repeat="link in question.links"> + <td>{{link.name}}</a></td> + <td>{{link.url}}</td> + <td> + <a class="btn fa fa-minus" title="Remove link" + ng-click="removeLink(link)"/> + <a class="btn fa fa-pencil" title="Edit link" + ng-click="modalEditLink(link)"/> + </td> + </tr> + </tbody> + </table> + </div> + + </div> + + <!-- End Line with Related Links --> + diff --git a/coselmar-ui/src/main/webapp/views/questions/viewquestion.html b/coselmar-ui/src/main/webapp/views/questions/viewquestion.html index d376fb0..5c2aaec 100644 --- a/coselmar-ui/src/main/webapp/views/questions/viewquestion.html +++ b/coselmar-ui/src/main/webapp/views/questions/viewquestion.html @@ -126,7 +126,23 @@ </table> </dd> </dl> + + <dl ng-if="question.links && question.links.length > 0"> + <dt>{{ 'question.metadata.links.display' | translate }}</dt> + <dd> + <ul> + <li ng-repeat="link in question.links"> + <a href="{{link.url}}" target="_blank"> + <span ng-if="link.name && link.name.length > 0">{{link.name}}</span> + <span ng-if="!link.name || link.name.length === ''">{{link.url}}</span> + </a> + </li> + </ul> + </dd> + </dl> + </div> + <div class="form-group col-md-4 aside"> <div> <dl> -- To stop receiving notification emails like this one, please contact codelutin.com SCM administrator <admin+scm@codelutin.com>.