Skip to main content
summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorjmisinco2014-07-17 16:17:16 +0000
committerRoberto E. Escobar2014-10-01 21:03:58 +0000
commite82e4f925c9e21503fa5435e50a163fe3240924e (patch)
tree3ff1cdf10b701a5d5e6dd288083ed867d27100c8
parentf0c3f9ce5dcfb5c15b0c4e17f71b1da20e2f01a8 (diff)
downloadorg.eclipse.osee-e82e4f925c9e21503fa5435e50a163fe3240924e.tar.gz
org.eclipse.osee-e82e4f925c9e21503fa5435e50a163fe3240924e.tar.xz
org.eclipse.osee-e82e4f925c9e21503fa5435e50a163fe3240924e.zip
feature[ats_ATS77015]: Add web UI for CPA
-rw-r--r--plugins/org.eclipse.osee.ats.rest/META-INF/MANIFEST.MF1
-rw-r--r--plugins/org.eclipse.osee.ats.rest/build.properties3
-rw-r--r--plugins/org.eclipse.osee.ats.rest/web/analyze.html90
-rw-r--r--plugins/org.eclipse.osee.ats.rest/web/js/analyzeCtrl.js197
-rw-r--r--plugins/org.eclipse.osee.ats.rest/web/js/app.js25
-rw-r--r--plugins/org.eclipse.osee.ats.rest/web/js/cpaFactory.js108
-rw-r--r--plugins/org.eclipse.osee.ats.rest/web/main.html51
7 files changed, 474 insertions, 1 deletions
diff --git a/plugins/org.eclipse.osee.ats.rest/META-INF/MANIFEST.MF b/plugins/org.eclipse.osee.ats.rest/META-INF/MANIFEST.MF
index 02fd1587540..db93fa28f86 100644
--- a/plugins/org.eclipse.osee.ats.rest/META-INF/MANIFEST.MF
+++ b/plugins/org.eclipse.osee.ats.rest/META-INF/MANIFEST.MF
@@ -6,6 +6,7 @@ Bundle-Version: 0.19.0.qualifier
Bundle-RequiredExecutionEnvironment: JavaSE-1.6
Bundle-Vendor: Eclipse Open System Engineering Environment
Service-Component: OSGI-INF/*.xml
+Osee-JaxRs-Resource: /web/*;path=/ats/cpa/ui
Import-Package: com.google.gson;version="2.1.0",
com.lowagie.text,
com.lowagie.text.html,
diff --git a/plugins/org.eclipse.osee.ats.rest/build.properties b/plugins/org.eclipse.osee.ats.rest/build.properties
index d9e9369c5db..49b1233e59d 100644
--- a/plugins/org.eclipse.osee.ats.rest/build.properties
+++ b/plugins/org.eclipse.osee.ats.rest/build.properties
@@ -3,4 +3,5 @@ output.. = bin/
bin.includes = META-INF/,\
.,\
OSGI-INF/,\
- REST-INF/
+ REST-INF/,\
+ web/
diff --git a/plugins/org.eclipse.osee.ats.rest/web/analyze.html b/plugins/org.eclipse.osee.ats.rest/web/analyze.html
new file mode 100644
index 00000000000..94d591fce59
--- /dev/null
+++ b/plugins/org.eclipse.osee.ats.rest/web/analyze.html
@@ -0,0 +1,90 @@
+<!DOCTYPE html>
+<html>
+<body>
+ <div class="container-fluid">
+ <div class="row col-lg-12 h4" ng-show="!selectedProject">
+ Select a project below to load:
+ </div>
+ <div class="row">
+ <div class="col-md-3 h4">
+ Project: <select ng-change="updateProject()" ng-model="selectedProject"
+ ng-options="item.name for item in projects"></select>
+ </div>
+ <div ng-show="selectedProject" class="col-md-2 h4">Analyzed: <strong>{{numAnalyzed()}}</strong></strong></div>
+ <div ng-show="selectedProject" class="col-md-2 h4">UnAnalyzed: <strong>{{items.length - numAnalyzed()}}</strong></strong></div>
+ <div ng-show="selectedProject" class="col-md-2 h4">Total: <strong>{{items.length}}</strong></div>
+ </div>
+ <div class="row col-lg-12" ng-show="selectedProject">
+ <div class="panel panel-primary">
+ <div class="panel-heading">
+ <span>
+ <strong>Edit:</strong>
+ <button type="button" class="btn btn-default btn-xs" ng-click="updateApplicabilities()" ng-disabled="!itemsSelected()"" >
+ Applicability</button>
+ <button type="button" class="btn btn-default btn-xs" ng-click="updateAssignees()" ng-disabled="!itemsSelected()" >
+ Assignees</button>
+ <button type="button" class="btn btn-default btn-xs" ng-click="updateRationale()" ng-disabled="!itemsSelected()" >
+ Rationale</button>
+ </span>
+ <span class="pull-right"><strong>{{itemsSelected()}}</strong> of {{items.length}} Selected
+ <button type="button" class="btn btn-default btn-xs" ng-click="updateProject()" >
+ <span class="glyphicon glyphicon-refresh"></span></button>
+ </span>
+ </div>
+ <div ng-show="items" style="height: 600px" class="gridStyle" ng-grid="gridOptions"></div>
+ </div>
+ </div>
+
+ <!-- definitions for modal forms -->
+ <script type="text/ng-template" id="editAssignees.html">
+ <div class="modal-header">
+ <h3 class="modal-title">Edit Assignees</h3>
+ <input class="form-control" type="search" ng-model="filter" placeholder="Search" focus-me>
+ </div>
+ <div class="modal-body" style="height: 400px; overflow: auto;">
+ <table class="table table-bordered">
+ <tr ng-repeat="item in items | filter:{name: filter}">
+ <td width="30" style="text-align: left">
+ <input type="checkbox" ng-model="item.$selected"/>
+ </td>
+ <td>
+ {{item.name}}
+ </td>
+ </tr>
+ </table>
+ </div>
+ <div class="modal-footer">
+ <button class="btn btn-primary" ng-click="ok()">OK</button>
+ <button class="btn btn-warning" ng-click="cancel()">Cancel</button>
+ </div>
+ </script>
+
+ <script type="text/ng-template" id="editRationale.html">
+ <div class="modal-header">
+ <h3 class="modal-title">Edit Rationale</h3>
+ </div>
+ <div class="modal-body">
+ <textarea class="form-control" rows="3" ng-model="newRationale.rationale" focus-me></textarea>
+ </div>
+ <div class="modal-footer">
+ <button class="btn btn-primary" ng-click="ok()">OK</button>
+ <button class="btn btn-warning" ng-click="cancel()">Cancel</button>
+ </div>
+ </script>
+
+ <script type="text/ng-template" id="editApplicability.html">
+ <div class="modal-header">
+ <h3 class="modal-title">Edit Applicability</h3>
+ </div>
+ <div class="modal-body">
+ <select ng-model="selected.applicability" ng-options="o as o for o in applicabilityEnum" focus-me></select>
+ </div>
+ <div class="modal-footer">
+ <button class="btn btn-primary" ng-click="ok()">OK</button>
+ <button class="btn btn-warning" ng-click="cancel()">Cancel</button>
+ </div>
+ </script>
+ </div>
+
+</body>
+</html> \ No newline at end of file
diff --git a/plugins/org.eclipse.osee.ats.rest/web/js/analyzeCtrl.js b/plugins/org.eclipse.osee.ats.rest/web/js/analyzeCtrl.js
new file mode 100644
index 00000000000..f0f66cf7e56
--- /dev/null
+++ b/plugins/org.eclipse.osee.ats.rest/web/js/analyzeCtrl.js
@@ -0,0 +1,197 @@
+/**
+ * Cpa Analyze Controller
+ */
+angular.module('CpaApp').controller('AnalyzeCtrl',
+ [ '$scope', 'CpaFactory', '$resource', '$window', '$modal', '$filter', function($scope, CpaFactory, $resource, $window, $modal, $filter) {
+
+ CpaFactory.getConfig().$promise.then(function(data) {
+ $scope.applicabilityEnum = [''].concat(data.applicabilityOptions);
+ });
+
+ $scope.projects = CpaFactory.getProjects();
+
+ var idCellTmpl = '<button class="btn btn-default btn-sm" ng-disabled="!row.entity.decisionLocation" ng-click="openLink(row.entity.decisionLocation)">{{row.getProperty(col.field)}}</button>';
+
+ var origCellTmpl = '<button class="btn btn-default btn-sm" ng-disabled="!row.entity.origPcrLocation" ng-click="openLink(row.entity.origPcrLocation)">{{row.getProperty(col.field)}}</button>';
+
+ var dupCellTmpl = '<button class="btn btn-default btn-sm" ng-show="row.entity.duplicatedPcrLocation" ng-disabled="!row.entity.duplicatedPcrLocation" ng-click="openLink(row.entity.duplicatedPcrLocation)">{{row.getProperty(col.field)}}</button>';
+
+ var applCellTmpl = '<div class="ngCellText" ng-class="col.colIndex()"><select ng-change="updateApplicability(row.entity)" ng-model="COL_FIELD" ng-options="o as o for o in applicabilityEnum"></select></div>';
+
+ $scope.selectedItems = [];
+
+ $scope.gridOptions = {data: 'items',
+ enableHighlighting: true,
+ selectedItems: $scope.selectedItems,
+ showSelectionCheckbox: true,
+ selectWithCheckboxOnly: true,
+ enableColumnResize: true,
+ showFilter: true,
+ sortInfo: {fields: ['uuid'], directions: ['asc']},
+ columnDefs: [{field: 'uuid', displayName: 'Id', width: 85, cellTemplate: idCellTmpl},
+ {field: 'pcrSystem', displayName: 'Type', width: 60},
+ {field: 'originatingPcr.programName', displayName: 'Original Project', width: 100, cellTemplate: origCellTmpl},
+ {field: 'originatingPcr.priority', displayName: 'Priority', width: 40},
+ {field: 'originatingPcr.title', displayName: 'Title', width: 300},
+ {field: 'applicability', displayName: 'Applicability', width: 70, cellTemplate: applCellTmpl},
+ {field: 'assignees', displayName: 'Assignees', width: 150},
+ {field: 'rationale', displayName: 'Rationale'},
+ {field: 'duplicatedPcrId', displayName: 'Duplicate Pcr', width: 70, enableCellEdit: true, cellTemplate: dupCellTmpl},
+ {field: 'completedDate', displayName: 'Completed Date', width: 90},
+ {field: 'completedBy', displayName: 'Completed By', width: 100}]
+ };
+
+ $scope.$on('ngGridEventEndCellEdit', function(evt){
+ // place holder for updating duplicated pcr id
+ });
+
+ $scope.updateProject = function() {
+ if($scope.selectedProject) {
+ $scope.items = null;
+ CpaFactory.getProjectCpas($scope.selectedProject).$promise.then(function(data){
+ $scope.items = data;
+ });
+ }
+ }
+
+ $scope.openLink = function(url) {
+ $window.open(url);
+ }
+
+ $scope.itemsSelected = function() {
+ return $scope.selectedItems.length;
+ }
+
+ $scope.numAnalyzed = function() {
+ var count = 0;
+ angular.forEach($scope.items, function(item) {
+ count += item.applicability ? 1 : 0;
+ });
+ return count;
+ }
+
+ $scope.getSelected = function(includeCompleted) {
+ var toUpdate = [];
+ for(var i = 0; i < $scope.selectedItems.length; i++) {
+ if(!$scope.selectedItems[i].applicability || (includeCompleted && $scope.selectedItems[i].applicability)) {
+ toUpdate.push($scope.selectedItems[i]);
+ }
+ }
+ return toUpdate;
+ }
+
+ $scope.updateApplicability = function(item) {
+ item.$selected = item.$selected && !item.applicability;
+ CpaFactory.updateApplicability(item, item.applicability);
+ }
+
+ $scope.updateAssignees = function() {
+ var modalInstance = $modal.open({
+ templateUrl: 'editAssignees.html',
+ controller: AssigneeModalCtrl,
+ size: 'sm',
+ resolve: {
+ items: function () {
+ return CpaFactory.getUsers();
+ }
+ }
+ });
+
+ modalInstance.result.then(function (selected) {
+ var toUpdate = $scope.getSelected();
+ CpaFactory.updateAssignees(toUpdate, selected);
+ });
+ }
+
+ var AssigneeModalCtrl = function ($scope, $modalInstance, items) {
+ $scope.items = items;
+
+ $scope.ok = function () {
+ var selected = [];
+ for(var i = 0; i < $scope.items.length; i++) {
+ if($scope.items[i].$selected) {
+ selected.push($scope.items[i]);
+ }
+ }
+ $modalInstance.close(selected);
+ };
+
+ $scope.cancel = function () {
+ $modalInstance.dismiss('cancel');
+ };
+ };
+
+ $scope.updateRationale = function() {
+ var toUpdate = $scope.getSelected();
+ var existing = "";
+ if(toUpdate.length === 1) {
+ existing = toUpdate[0].rationale;
+ }
+ var modalInstance = $modal.open({
+ templateUrl: 'editRationale.html',
+ controller: RationaleModalCtrl,
+ resolve: {
+ existing: function () {
+ return existing;
+ }
+ }
+ });
+
+ modalInstance.result.then(function (rationale) {
+ CpaFactory.updateRationale(toUpdate, rationale);
+ });
+ }
+
+ var RationaleModalCtrl = function ($scope, $modalInstance, existing) {
+
+ $scope.newRationale = {rationale: existing};
+
+ $scope.ok = function () {
+ $modalInstance.close($scope.newRationale.rationale);
+ };
+
+ $scope.cancel = function () {
+ $modalInstance.dismiss('cancel');
+ };
+ };
+
+ $scope.updateApplicabilities = function() {
+ var toUpdate = $scope.getSelected(true);
+ var existing = "";
+ if(toUpdate.length === 1) {
+ existing = toUpdate[0].applicability;
+ }
+ var modalInstance = $modal.open({
+ templateUrl: 'editApplicability.html',
+ controller: ApplicabilityModalCtrl,
+ size: 'sm',
+ resolve: {
+ existing: function () {
+ return existing;
+ },
+ applicabilityEnum: function() {
+ return $scope.applicabilityEnum;
+ }
+ }
+ });
+
+ modalInstance.result.then(function (applicability) {
+ CpaFactory.updateApplicability(toUpdate, applicability);
+ });
+ };
+
+ var ApplicabilityModalCtrl = function ($scope, $modalInstance, existing, applicabilityEnum) {
+
+ $scope.applicabilityEnum = applicabilityEnum;
+ $scope.selected = {applicability: existing};
+
+ $scope.ok = function () {
+ $modalInstance.close($scope.selected.applicability);
+ };
+
+ $scope.cancel = function () {
+ $modalInstance.dismiss('cancel');
+ };
+ };
+
+ } ]); \ No newline at end of file
diff --git a/plugins/org.eclipse.osee.ats.rest/web/js/app.js b/plugins/org.eclipse.osee.ats.rest/web/js/app.js
new file mode 100644
index 00000000000..19403c88dd1
--- /dev/null
+++ b/plugins/org.eclipse.osee.ats.rest/web/js/app.js
@@ -0,0 +1,25 @@
+/**
+ * Cpa app definition
+ */
+var app = angular.module('CpaApp', [ 'ngRoute', 'ngResource', 'ui.bootstrap', 'ngGrid' ]);
+
+app.config([ '$routeProvider', function($routeProvider) {
+ $routeProvider.when('/', {
+ redirectTo : "/analyze",
+ }).when('/analyze', {
+ templateUrl : 'analyze.html',
+ controller : 'AnalyzeCtrl'
+ }).otherwise({
+ redirectTo : "/analyze"
+ });
+} ]);
+
+app.directive('focusMe', function($timeout) {
+ return function(scope, element, attrs) {
+ scope.$watch(attrs.focusMe, function() {
+ $timeout(function() {
+ element[0].focus();
+ }, 20);
+ });
+ };
+ }); \ No newline at end of file
diff --git a/plugins/org.eclipse.osee.ats.rest/web/js/cpaFactory.js b/plugins/org.eclipse.osee.ats.rest/web/js/cpaFactory.js
new file mode 100644
index 00000000000..54793d52cee
--- /dev/null
+++ b/plugins/org.eclipse.osee.ats.rest/web/js/cpaFactory.js
@@ -0,0 +1,108 @@
+/**
+ * Cpa Factory
+ */
+
+angular.module('CpaApp').factory('CpaFactory', ['$resource', function($resource) {
+
+ var factory = {};
+
+ var projectResource = $resource('/ats/cpa/program');
+ var projectCpaResource = $resource('/ats/cpa/program/:uuid');
+ var userResource = $resource('/ats/user', {active: 'Active'});
+ var configResource = $resource('/ats/cpa/config');
+ var decisionResource = $resource('/ats/cpa/decision');
+
+ var users = userResource.query();
+ var config = configResource.get();
+
+ factory.getConfig = function() {
+ return config;
+ }
+
+ factory.getProjects = function() {
+ return projectResource.query();
+ }
+
+ factory.getProjectCpas = function(project) {
+ return projectCpaResource.query(project)
+ }
+
+ factory.getUsers = function() {
+ return users;
+ }
+
+ factory.updateAssignees = function(cpas, newAssignees) {
+ var cpaArr = cpas instanceof Array ? cpas : [cpas];
+ var assigneeArr = newAssignees instanceof Array ? newAssignees : [newAssignees];
+
+ var toPost = {};
+ toPost.uuids = [];
+ toPost.assignees = [];
+
+ var assigneeStr = "";
+ for(var i = 0; i < newAssignees.length; i++) {
+ assigneeStr += newAssignees[i].name + ";";
+ toPost.assignees.push(newAssignees[i].uuid);
+ }
+ assigneeStr = assigneeStr.slice(0, -1);
+
+ for(var i = 0; i < cpas.length; i++) {
+ toPost.uuids.push(cpas[i].uuid);
+ }
+
+ decisionResource.save(toPost, function() {
+ for(var i = 0; i < cpas.length; i++) {
+ cpas[i].assignees = assigneeStr;
+ }
+ });
+
+ }
+
+ factory.updateRationale = function(cpas, newRationale) {
+ var cpaArr = cpas instanceof Array ? cpas : [cpas];
+
+ var toPost = {};
+ toPost.uuids = [];
+ toPost.rationale = newRationale;
+
+ for(var i = 0; i < cpas.length; i++) {
+ toPost.uuids.push(cpas[i].uuid);
+ }
+
+ decisionResource.save(toPost, function() {
+ for(var i = 0; i < cpas.length; i++) {
+ cpas[i].rationale = newRationale;
+ }
+ }, function(err){
+ for(var i = 0; i < cpas.length; i++) {
+ cpas[i].rationale = "Err - Refresh Table";
+ }
+ });
+
+ }
+
+ factory.updateApplicability = function(item, applicability) {
+ var items = item instanceof Array ? item : [item];
+ var toPost = {};
+ toPost.uuids = [];
+ toPost.applicability = applicability;
+
+ for(var i = 0; i < items.length; i++) {
+ toPost.uuids.push(items[i].uuid);
+ }
+
+ decisionResource.save(toPost, function() {
+ for(var i = 0; i < items.length; i++) {
+ items[i].applicability = applicability;
+ }
+ }, function(err){
+ for(var i = 0; i < items.length; i++) {
+ items[i].applicability = "Err - Refresh Table";
+ }
+ });
+
+ }
+
+ return factory;
+
+}]); \ No newline at end of file
diff --git a/plugins/org.eclipse.osee.ats.rest/web/main.html b/plugins/org.eclipse.osee.ats.rest/web/main.html
new file mode 100644
index 00000000000..39ca17c0370
--- /dev/null
+++ b/plugins/org.eclipse.osee.ats.rest/web/main.html
@@ -0,0 +1,51 @@
+<!DOCTYPE html>
+<html>
+<head>
+<meta charset="UTF-8">
+<title>Cross Project Applicability</title>
+<link rel="stylesheet" href="/lib/css/bootstrap.min.css">
+<link rel="stylesheet" type="text/css" href="http://cdnjs.cloudflare.com/ajax/libs/ng-grid/2.0.11/ng-grid.min.css" />
+</head>
+<body ng-app="CpaApp">
+
+ <nav class="navbar navbar-default" role="navigation">
+ <div class="container-fluid">
+ <div class="navbar-header">
+ <button type="button" class="navbar-toggle" data-toggle="collapse" data-target="#bs-example-navbar-collapse-1">
+ <span class="sr-only">Toggle navigation</span>
+ <span class="icon-bar"></span>
+ <span class="icon-bar"></span>
+ <span class="icon-bar"></span>
+ </button>
+ <a class="navbar-brand" href="#/analyze">Cross Project Applicability</a>
+ </div>
+ <div class="collapse navbar-collapse" ng-controller="HeaderController">
+ <ul class="nav navbar-nav navbar-right">
+ <li ng-class="{ active: isActive('/analyze')}"><a href="#/analyze">Analyze</a></li>
+ </ul>
+ </div>
+ </div>
+ </nav>
+
+ <div ng-view></div>
+
+ <script>
+ function HeaderController($scope, $location) {
+ $scope.isActive = function(viewLocation) {
+ return viewLocation === $location.path();
+ };
+ }
+ </script>
+
+ <script src="/lib/js/jquery-2.0.3.min.js"></script>
+ <script src="/lib/js/angular.min.js"></script>
+ <script src="/lib/js/angular-route.min.js"></script>
+ <script src="/lib/js/angular-resource.min.js"></script>
+ <script src="http://cdnjs.cloudflare.com/ajax/libs/ng-grid/2.0.11/ng-grid.min.js"></script>
+ <script src="/lib/js/bootstrap.min.js"></script>
+ <script src="/lib/js/ui-bootstrap-tpls-0.11.0.min.js"></script>
+ <script src="js/app.js"></script>
+ <script src="js/cpaFactory.js"></script>
+ <script src="js/analyzeCtrl.js"></script>
+</body>
+</html> \ No newline at end of file

Back to the top