Skip to content
This repository has been archived by the owner on Oct 16, 2023. It is now read-only.

Commit

Permalink
Merge branch 'gh-496-save-graph-changes' of https://github.com/gchq/g…
Browse files Browse the repository at this point in the history
…affer-tools into gh-496-save-graph-changes
  • Loading branch information
p013570 committed Jan 28, 2020
2 parents 0387cfc + e11a172 commit c98368f
Show file tree
Hide file tree
Showing 13 changed files with 689 additions and 5 deletions.
22 changes: 22 additions & 0 deletions ui/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ UI
- [Operation options](#operation-options)
- [Quick Query](#quick-query)
- [Graph](#graph)
- [Saved Results](#saved-results)
- [Feedback](#feedback)
6. [Testing](#testing)

Expand Down Expand Up @@ -780,6 +781,27 @@ We have all the material design icons [here](https://github.com/gchq/gaffer-tool
If you're using a simple string or number as your vertex, use "undefined" as your key. Otherwise you'll need to use the field
name specified in the [types section](#types).

### Saved Results

You can configure the UI to allow results to be saved. The results are stored using the Gaffer ExportToGafferResultCache
and GetGafferResultCacheExport operations, which if configured, will store the results in a separate Gaffer graph.

This UI feature then adds a cookie 'savedResults' which contains the IDs of the user's saved results.

```json
"savedResults": {
"enabled": true,
"key": "savedResults",
"timeToLiveInDays": 7
},
```

| name | type | description
|----------------------|----------|---------------------------------------------------------
| enabled | boolean | If true then the feature is enabled
| key | string | The cookie key
| timeToLiveInDays | number | The number of days the cookie should be kept for.


### Feedback

Expand Down
8 changes: 8 additions & 0 deletions ui/dependencies/lib/angular/js/angular-cookies.min.js

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 2 additions & 0 deletions ui/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -109,6 +109,7 @@
<source>${project.build.directory}/${project.build.finalName}/lib/angular/js/angular-route.min.js</source>
<source>${project.build.directory}/${project.build.finalName}/lib/angular/js/angular-mocks.min.js</source>
<source>${project.build.directory}/${project.build.finalName}/lib/angular/js/angular-sanitize.min.js</source>
<source>${project.build.directory}/${project.build.finalName}/lib/angular/js/angular-cookies.min.js</source>
<source>${project.build.directory}/${project.build.finalName}/lib/cytoscape/js/cytoscape.min.js</source>
<source>${project.build.directory}/${project.build.finalName}/lib/cytoscape/js/cytoscape-ngraph.forcelayout.js</source>
<source>${project.build.directory}/${project.build.finalName}/lib/jquery/js/jquery.min.js</source>
Expand Down Expand Up @@ -500,6 +501,7 @@
<source>dependencies/lib/angular/js/angular-route.min.js</source>
<source>dependencies/lib/angular/js/angular-mocks.min.js</source>
<source>dependencies/lib/angular/js/angular-sanitize.min.js</source>
<source>dependencies/lib/angular/js/angular-cookies.min.js</source>
<source>dependencies/lib/cytoscape/js/cytoscape.min.js</source>
<source>dependencies/lib/cytoscape/js/cytoscape-ngraph.forcelayout.js</source>
<source>dependencies/lib/jquery/js/jquery.min.js</source>
Expand Down
2 changes: 1 addition & 1 deletion ui/src/main/webapp/app/app.js
Original file line number Diff line number Diff line change
Expand Up @@ -16,4 +16,4 @@

'use strict';

angular.module('app', ['ngMaterial', 'ngRoute', 'md.data.table', 'ngMessages', 'ngAnimate', 'ngSanitize', 'chart.js']);
angular.module('app', ['ngMaterial', 'ngRoute', 'md.data.table', 'ngMessages', 'ngAnimate', 'ngSanitize', 'chart.js', 'ngCookies']);
6 changes: 6 additions & 0 deletions ui/src/main/webapp/app/config/route-config.js
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,12 @@ angular.module('app').config(['$locationProvider', '$routeProvider', function($l
icon: 'raw',
inNav: true
})
.when('/saved-data', {
title: 'Saved Data',
template: '<saved-results></saved-results>',
icon: 'save',
inNav: true
})
.when('/settings', {
title: 'Settings',
template: '<settings-view></settings-view>',
Expand Down
168 changes: 168 additions & 0 deletions ui/src/main/webapp/app/saved-results/saved-results-component.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,168 @@
/*
* Copyright 2020 Crown Copyright
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

'use strict';

angular.module('app').component('savedResults', savedResults())

function savedResults() {
return {
templateUrl: 'app/saved-results/saved-results.html',
controller: SavedResultsController,
controllerAs: 'ctrl'
}
}

function SavedResultsController(loading, query, graph, error, navigation, events, $cookies, config) {
var saveResultsConfig = {
enabled: false
};

var vm = this;
vm.savedResults = [];

/**
* Loads the saved results
*/
vm.$onInit = function() {
events.subscribe('resultsSaved', function() {
vm.savedResults = loadSavedResults();
});

config.get().then(function(conf) {
if (conf.savedResults) {
saveResultsConfig = conf.savedResults;
if(saveResultsConfig.enabled) {
vm.savedResults = loadSavedResults();
}
}
});
}

vm.updateSavedResults = function() {
updateSavedResults(vm.savedResults);
vm.savedResults = loadSavedResults();
}

vm.deleteSavedResults = function(jobId) {
deleteSavedResults(jobId);
vm.savedResults = loadSavedResults();
}

vm.deleteAllSavedResults = function() {
vm.savedResults = []
updateSavedResults(vm.savedResults);
}

vm.reloadSavedResults = function(jobId) {
loading.load();

query.executeQuery(
{
"class": "uk.gov.gchq.gaffer.operation.impl.export.resultcache.GetGafferResultCacheExport",
"jobId": jobId
},
function(data) {
submitResults(data);
}
);

var submitResults = function(data) {
if(!data || data.length < 1) {
error.handle('No results were found - this could be because your results have expired.');
} else {
graph.deselectAll();
navigation.goTo('results');
}
}
}

vm.isEnabled = function() {
return saveResultsConfig.enabled;
}

vm.daysToLive = function() {
if(vm.isEnabled() && saveResultsConfig.timeToLiveInDays) {
if(saveResultsConfig.timeToLiveInDays == 1) {
return "1 day"
}
return saveResultsConfig.timeToLiveInDays + " days";
}
return "0 days";
}

var loadSavedResults = function(query) {
var savedResults = $cookies.getObject(saveResultsConfig.key);
if(!savedResults) {
savedResults = [];
}
removeExpired(savedResults);
sortSavedResults(savedResults);
return savedResults;
}

var deleteSavedResults = function(jobId) {
var savedResults = loadSavedResults();
for( var i = 0; i < savedResults.length; i++){
if (savedResults[i].jobId === jobId) {
savedResults.splice(i, 1);
}
}
updateSavedResults(savedResults);
}

var updateSavedResults = function(savedResults) {
for( var i = 0; i < savedResults.length; i++){
savedResults[i].edit = false;
}
$cookies.putObject(saveResultsConfig.key, savedResults, getExpiry());
}

var sortSavedResults = function(savedResults) {
savedResults.sort(function(a, b) {
return a.timestamp > b.timestamp ? -1 : (a.timestamp < b.timestamp ? 1 : 0);
})
}

var removeExpired = function(savedResults) {
var ttl = saveResultsConfig.timeToLiveInDays;
if(!ttl) {
return;
}
var ttlInMillis = ttl * 24 * 60 * 60 * 1000;
var removedItem = false;
var now = new Date().getTime();
for(var i = 0; i < savedResults.length; i++){
if (savedResults[i].timestamp + ttlInMillis < now) {
savedResults.splice(i, 1);
removedItem = true;
}
}
if(removedItem) {
updateSavedResults(savedResults);
}
}

var getExpiry = function() {
var result = new Date();
var ttl = saveResultsConfig.timeToLiveInDays;
if(!ttl) {
ttl = 7;
}
result.setDate(result.getDate() + ttl);
return result.toUTCString();
}
}
86 changes: 86 additions & 0 deletions ui/src/main/webapp/app/saved-results/saved-results.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
<!--
~ Copyright 2020 Crown Copyright
~
~ Licensed under the Apache License, Version 2.0 (the "License");
~ you may not use this file except in compliance with the License.
~ You may obtain a copy of the License at
~
~ http://www.apache.org/licenses/LICENSE-2.0
~
~ Unless required by applicable law or agreed to in writing, software
~ distributed under the License is distributed on an "AS IS" BASIS,
~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
~ See the License for the specific language governing permissions and
~ limitations under the License.
-->

<div layout="row" layout-padding>
<div flex-offset-gt-sm="20" flex-gt-sm="60" flex="100">
<div layout="column" flex>
<h3 class="md-headline">
Saved Data
<md-button ng-show="ctrl.isEnabled()" class="md-primary md-icon-button" ng-click="ctrl.deleteAllSavedResults()">
<md-icon md-svg-icon="delete"></md-icon>
<md-tooltip>Delete all results</md-tooltip>
</md-button>
</h3>
<p ng-show="ctrl.isEnabled()" class="padding-bottom">
Any results you save, using the 'Save' button on the toolbar at the top, will be listed here.
The results are cached on a server and will automatically expire after {{ ctrl.daysToLive() }}.
This list of saved result IDs is cached in your current browser and will not be available in another browser or computer.
</p>
<p ng-show="!ctrl.isEnabled()" class="padding-bottom">Saving results is currently disabled</p>

<div ng-show="ctrl.isEnabled() && ctrl.savedResults.length == 0">
<md-card flex>
<md-card-title>
<md-card-title-text>
<span class="md-headline">No saved results</span>
</md-card-title-text>
</md-card-title>
<md-card-content>
It doesn't look like you've got any saved results. You can use the 'Save' button on the toolbar
at the top to save your results.
</md-card-content>
</md-card>
</div>

<div ng-show="ctrl.isEnabled()" ng-repeat="savedResult in ctrl.savedResults">
<md-card flex>
<md-card-header>
<md-card-avatar>
<md-icon md-svg-icon="save"></md-icon>
</md-card-avatar>
<md-card-header-text>
<span ng-click="savedResult.edit = true" class="md-title" ng-show="!savedResult.edit">{{savedResult.localId}}</span>
<md-input-container class="md-secondary no-errors no-margin" ng-show="savedResult.edit">
<input type="text"
ng-model="savedResult.localId"
aria-label="Edit saved results ID"
ng-blur="ctrl.updateSavedResults()"
class="md-title">
</md-input-container>
<span class="md-subhead">ID: {{savedResult.jobId}}</span>
</md-card-header-text>
<md-button ng-show="savedResult.edit" class="md-primary md-icon-button" ng-click="savedResult.edit = false">
<md-icon md-svg-icon="save"></md-icon>
<md-tooltip>Save</md-tooltip>
</md-button>
<md-button ng-show="!savedResult.edit" class="md-primary md-icon-button" ng-click="savedResult.edit = true">
<md-icon md-svg-icon="edit"></md-icon>
<md-tooltip>Rename</md-tooltip>
</md-button>
<md-button class="md-primary md-icon-button" ng-click="ctrl.deleteSavedResults(savedResult.jobId)">
<md-icon md-svg-icon="delete"></md-icon>
<md-tooltip>Delete results</md-tooltip>
</md-button>
<md-button class="md-primary md-icon-button" ng-click="ctrl.reloadSavedResults(savedResult.jobId)">
<md-icon md-svg-icon="open-in-new"></md-icon>
<md-tooltip>Reload results</md-tooltip>
</md-button>
</md-card-header>
</md-card>
</div>
</div>
</div>
</div>
Loading

0 comments on commit c98368f

Please sign in to comment.