Skip to content
This repository has been archived by the owner on Dec 22, 2022. It is now read-only.

Commit

Permalink
Adds ability to enter values and call a service to test interactively
Browse files Browse the repository at this point in the history
The rule viewer now supports entering values for Facts when viewing a
Berekening. It is a first version of using the viewer as an interactive
testing tool. There are definitely improvements to be made to the
usability, but it works :)
  • Loading branch information
jhkuperus committed Feb 3, 2017
1 parent 197c954 commit 5cc6352
Show file tree
Hide file tree
Showing 7 changed files with 310 additions and 36 deletions.
25 changes: 25 additions & 0 deletions app/controllers/ConfigurationController.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
package controllers

import scala.collection.JavaConverters._

import javax.inject._

import play.api.Configuration
import play.api.libs.json._
import play.api.mvc._


//scalastyle:off public.methods.have.type

@Singleton
class ConfigurationController @Inject()(configuration: Configuration) extends Controller {

val config: Map[String, List[String]] = Map[String, List[String]](
"endpoints" -> configuration.getStringList("endpoints").map( _.asScala.toList ).getOrElse( List[String]() )
)

def all = Action {
Ok(Json.toJson(config))
}

}
5 changes: 5 additions & 0 deletions conf/application.conf
Original file line number Diff line number Diff line change
Expand Up @@ -17,3 +17,8 @@ sources.root = "/public/sources/"
jars.load = [
// Add location to JARs containing Glossaries and Berekeningen
]

endpoints = [
// Add endpoint URLs for Scala Rules-Rest instances, e.g.:
// "http://localhost:9001/api/run/group/all"
]
2 changes: 1 addition & 1 deletion conf/routes
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ GET /api/jars/:id cont
GET /api/meta/jars controllers.JarsController.listConfiguration
GET /api/meta/jars/:id controllers.JarsController.configurationById(id)


GET /api/meta/config controllers.ConfigurationController.all

# Routes for static parts of the application

Expand Down
2 changes: 1 addition & 1 deletion public/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@
<button class="btn" ng-click="goHome()">Home</button>
<select class="form-control" ng-model="selectedBerekening" ng-change="jumpToBerekening()">
<option value="--not-selected--">Snel naar een berekening...</option>
<option ng-repeat="b in berekeningen | orderBy:'name' track by b.name" value="{{b.name}}">{{b.name|javatype}}</option>
<option ng-repeat="b in berekeningen | orderBy:'displayName' track by b.name" value="{{b.name}}">{{b.displayName}}</option>
</select>
</form>
</div>
Expand Down
181 changes: 168 additions & 13 deletions public/javascripts/berekeningen-app.js
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,23 @@
}
};
});

app.filter('scalatype', function() {
return function(input) {
if (input) {
var elems = input.split('.');
var name = elems[elems.length - 1];
if (name[name.length - 1] == '$') {
name = name.substr(0, name.length - 1);
}
return name;
}
else {
return '';
}
};
});

app.filter('usages', function() {
var signIn = '<i class="fa fa-fw fa-sign-in" title="Gebruikt als invoer"></i>';
var signOut = '<i class="fa fa-fw fa-sign-out" title="Gebruikt als uitvoer"></i>';
Expand Down Expand Up @@ -107,39 +124,59 @@
}
}]);

app.controller('HeaderController', ['$scope', '$q', '$location', 'BerekeningenService', 'GlossaryService', HeaderController]);
app.controller('HeaderController', ['$scope', '$q', '$location', 'BerekeningenService', 'GlossaryService', 'ExecutionService', HeaderController]);
app.controller('DashboardController', ['$scope', '$q', 'BerekeningenService', 'GlossaryService', 'UsedByService', DashboardController]);
app.controller('BerekeningController', ['$scope', '$routeParams', '$q', 'BerekeningenService', 'GlossaryService', 'UsedByService', BerekeningController]);
app.controller('BerekeningController', ['$scope', '$routeParams', '$q', 'BerekeningenService', 'GlossaryService', 'UsedByService', 'ExecutionService', BerekeningController]);

app.factory('GlossaryService', ['$http', GlossaryService]);
app.factory('BerekeningenService', ['$http', '$q', BerekeningenService]);
app.factory('BerekeningenService', ['$http', '$q', '$filter', BerekeningenService]);
app.factory('UsedByService', ['$q', 'GlossaryService', 'BerekeningenService', UsedByService]);
app.factory('ExecutionService', ['$http', ExecutionService]);

function BerekeningController($scope, $routeParams, $q, BerekeningenService, GlossaryService, UsedByService) {
function BerekeningController($scope, $routeParams, $q, BerekeningenService, GlossaryService, UsedByService, ExecutionService) {
var nameComponents = $routeParams.id.split('.');
$scope.berekeningId = $routeParams.id;
$scope.berekeningName = nameComponents.pop();
$scope.berekeningPackage = nameComponents;
$scope.showLabels = true;
$scope.showConditions = true;
$scope.showEvaluations = true;
$scope.showGraphAndSource = 'graphOnly';
$scope.toggles = {
showLabels: true,
showConditions: true,
showEvaluations: true,
showGraphAndSource: 'graphOnly',
showIntermediates: false,
showExecutionConfig: false,
hasExecutionHistory: false,
showLoadingIndicator: false,
showInputFields: true
};
$scope.berekeningInputs = [];
$scope.berekeningOutputs = [];
$scope.berekeningIntermediates = [];
$scope.context = {};
$scope.originalInput = {};
$scope.endpoints = ExecutionService.endpoints();
$scope.selectedEndpoint;

ExecutionService.loaded().then(function() {
if (ExecutionService.endpoints().length > 0) {
$scope.selectedEndpoint = ExecutionService.endpoints()[0];
}
});

var getBerekeningPromise = BerekeningenService.getBerekening($scope.berekeningId).then(function(berekening) {
$scope.berekening = berekening;
$scope.selectedNode = undefined;
$scope.hoveredNode = undefined;

initBerekeningGraph(document.getElementById('berekeningenGraafChart'), berekening, GlossaryService.dictionary(), $scope, 'selectedNode', 'hoveredNode');
}, function() {
console.error('No berekening found');
}, function(err) {
console.error('No berekening found', err);
});

$q.all([getBerekeningPromise, GlossaryService.loaded()]).then(function() {
$scope.berekening.inputs.forEach(function(i) { $scope.berekeningInputs.push(GlossaryService.dictionary()[$scope.berekening.nodes[i].name]); });
$scope.berekening.outputs.forEach(function(i) { $scope.berekeningOutputs.push(GlossaryService.dictionary()[$scope.berekening.nodes[i].name]); });
$scope.berekening.intermediates.forEach(function(i) { $scope.berekeningIntermediates.push(GlossaryService.dictionary()[$scope.berekening.nodes[i].name]); });
});

$scope.activeFact = undefined;
Expand All @@ -148,6 +185,79 @@
$scope.activeFact = f;
};

$scope.calculate = {
hasNoValuesInContext: !angular.equals($scope.context, {}),
lastResultSuccess: false,
lastResultErrors: {},
execute: function() {
$scope.toggles.hasExecutionHistory = true;
$scope.toggles.showLoadingIndicator = true;
sanitizeContext($scope.context);
copyContextValuesFromSource($scope.originalInput, $scope.context);
ExecutionService.execute($scope.selectedEndpoint, $scope.context).then(function(response) {
$scope.toggles.showLoadingIndicator = false;
$scope.calculate.lastResultSuccess = response.status === 200;
$scope.calculate.lastResultErrors = [];
if (response.data) {
if ( response.status === 200 ) {
copyContextValuesFromSource($scope.context, response.data.facts);
}
else {
response.data.obj.forEach(function(errorMessage) {
$scope.calculate.lastResultErrors.push(errorMessage.msg);
});
}
}
}).catch(function(err) {
$scope.toggles.showLoadingIndicator = false;
$scope.calculate.lastResultSuccess = false;
$scope.calculate.lastResultErrors = [
'Algemene fout bij uitvoeren servicer: ' + err
];
});
},
resetInput: function() {
copyContextValuesFromSource($scope.context, $scope.originalInput);
},
resetAll: function() {
copyContextValuesFromSource($scope.context, {});
copyContextValuesFromSource($scope.originalInput, {});
}
};

$scope.$watch(function() {
var oldContext = {}, contextChanged = false, changeCounter = 0;
return function() {
contextChanged = !angular.equals($scope.context, oldContext);
copyContextValuesFromSource(oldContext, $scope.context);
console.log('Checking context', contextChanged, changeCounter);
return contextChanged ? ++changeCounter : changeCounter;
};
}(), function() {
$scope.calculate.hasNoValuesInContext = angular.equals($scope.context, {});
});

function copyContextValuesFromSource(target, template) {
for ( var p in target ) {
if (target.hasOwnProperty(p) && !template.hasOwnProperty(p)) {
delete target[p];
}
}
for ( var p in template ) {
if (template.hasOwnProperty(p)) {
target[p] = template[p];
}
}
}

function sanitizeContext(target) {
for ( var p in target ) {
if (target.hasOwnProperty(p) && target[p] === '') {
delete target[p];
}
}
}

$scope.$watch(function() {
return '' + $scope.selectedNode + ':' + $scope.hoveredNode;
}, function() {
Expand Down Expand Up @@ -184,7 +294,7 @@
}

var NOT_SELECTED_A_BEREKENING = '--not-selected--';
function HeaderController($scope, $q, $location, BerekeningenService, GlossaryService) {
function HeaderController($scope, $q, $location, BerekeningenService, GlossaryService, ExecutionService) {
$scope.stillLoading = true;
$scope.berekeningen = BerekeningenService.berekeningen();
$scope.selectedBerekening = NOT_SELECTED_A_BEREKENING;
Expand All @@ -200,7 +310,7 @@
$location.url('/');
};

$q.all([BerekeningenService.loaded(), GlossaryService.loaded()]).then(function() {
$q.all([BerekeningenService.loaded(), GlossaryService.loaded(), ExecutionService.loaded()]).then(function() {
$scope.stillLoading = false;
});
}
Expand Down Expand Up @@ -256,6 +366,8 @@
var fact = glossary[p];
fact.usedIn = {};
fact.containedIn = g;
fact.id = 'fact-' + g + '-' + p;
fact.glossary = g;
newFacts.push(fact);
squashedGlossaries[fact.name] = fact;
}
Expand All @@ -268,7 +380,7 @@
}
}

function BerekeningenService($http, $q) {
function BerekeningenService($http, $q, $filter) {
var allBerekeningen = [{ name: 'Loading...' }];
var berekeningen = {};
var loadingPromise = reloadBerekeningen();
Expand Down Expand Up @@ -317,6 +429,7 @@
if ( bs.hasOwnProperty(p) ) {
var berekening = bs[p];
berekening.name = p;
berekening.displayName = $filter('scalatype')(p);

newBerekeningen.push(bs[p]);
berekeningen[p] = bs[p];
Expand Down Expand Up @@ -358,4 +471,46 @@
return {};
}

function ExecutionService($http) {
var availableEndpoints = [];
var loadingPromise = reloadEndpoints();

return {
endpoints: function() {
return availableEndpoints;
},
loaded: function() {
return loadingPromise
},
execute: function(endpoint, context) {
return callService(endpoint, context);
}
};

function reloadEndpoints() {
return $http({
method: 'GET',
url: 'api/meta/config'
}).then(function(response) {
availableEndpoints = response.data.endpoints;
}, function(err) {
console.error('Error retrieving configuration', err);
});
}

function callService(url, context) {
return $http({
method: 'POST',
url: url,
data: context
}).then(function(response) {
return response;
}, function(err) {
console.error('Error calling into service at url', url, 'Error message:', err);
return err;
});
}

}

})();

0 comments on commit 5cc6352

Please sign in to comment.