Author: ijd
Date: Thu Jun 19 17:52:25 2014
New Revision: 1603977
URL: http://svn.apache.org/r1603977
Log:
First cut at launching and tracking backup tasks
Added:
jena/Experimental/jena-fuseki2/src/main/webapp/js/app/models/task.js
Modified:
jena/Experimental/jena-fuseki2/src/main/webapp/js/app/main.manage.js
jena/Experimental/jena-fuseki2/src/main/webapp/js/app/models/dataset.js
jena/Experimental/jena-fuseki2/src/main/webapp/js/app/templates/dataset-management.tpl
jena/Experimental/jena-fuseki2/src/main/webapp/js/app/views/dataset-management.js
Modified: jena/Experimental/jena-fuseki2/src/main/webapp/js/app/main.manage.js
URL:
http://svn.apache.org/viewvc/jena/Experimental/jena-fuseki2/src/main/webapp/js/app/main.manage.js?rev=1603977&r1=1603976&r2=1603977&view=diff
==============================================================================
--- jena/Experimental/jena-fuseki2/src/main/webapp/js/app/main.manage.js
(original)
+++ jena/Experimental/jena-fuseki2/src/main/webapp/js/app/main.manage.js Thu
Jun 19 17:52:25 2014
@@ -7,6 +7,7 @@ define( ['require', '../common-config'],
'sprintf', 'bootstrap',
'app/models/fuseki-server',
'app/models/dataset',
+ 'app/models/task',
'app/views/dataset-management',
'app/services/ping-service',
'jquery.xdomainrequest'
Modified:
jena/Experimental/jena-fuseki2/src/main/webapp/js/app/models/dataset.js
URL:
http://svn.apache.org/viewvc/jena/Experimental/jena-fuseki2/src/main/webapp/js/app/models/dataset.js?rev=1603977&r1=1603976&r2=1603977&view=diff
==============================================================================
--- jena/Experimental/jena-fuseki2/src/main/webapp/js/app/models/dataset.js
(original)
+++ jena/Experimental/jena-fuseki2/src/main/webapp/js/app/models/dataset.js Thu
Jun 19 17:52:25 2014
@@ -9,7 +9,8 @@ define(
Backbone = require( "backbone" ),
_ = require( "underscore" ),
fui = require( "app/fui" ),
- sprintf = require( "sprintf" );
+ sprintf = require( "sprintf" ),
+ Task = require( "app/models/task" );
/**
* This model represents the core representation of the remote Fuseki
@@ -90,6 +91,20 @@ define(
url: this.mgmtActionURL(),
type: 'DELETE'
} );
+ },
+
+ /** Perform the action of taking a backup of this dataset */
+ backupDataset: function() {
+ var backupURL = sprintf( "%s/$/backup%s", this.baseURL(), this.name()
);
+ var ds = this;
+
+ return $.ajax( {
+ url: backupURL,
+ type: 'POST'
+ } )
+ .done( function( taskDescription ) {
+ new Task( ds, "backup", taskDescription );
+ } );
}
} );
Added: jena/Experimental/jena-fuseki2/src/main/webapp/js/app/models/task.js
URL:
http://svn.apache.org/viewvc/jena/Experimental/jena-fuseki2/src/main/webapp/js/app/models/task.js?rev=1603977&view=auto
==============================================================================
--- jena/Experimental/jena-fuseki2/src/main/webapp/js/app/models/task.js (added)
+++ jena/Experimental/jena-fuseki2/src/main/webapp/js/app/models/task.js Thu
Jun 19 17:52:25 2014
@@ -0,0 +1,105 @@
+/**
+ * A long-running task, which periodically pings the server for its task status
+ */
+
+define(
+ function( require ) {
+ "use strict";
+
+ var Marionette = require( "marionette" ),
+ Backbone = require( "backbone" ),
+ _ = require( "underscore" ),
+ fui = require( "app/fui" ),
+ sprintf = require( "sprintf" );
+
+ /* Constants */
+
+ var MS = 1000;
+ var MAX_DELAY = 10 * MS;
+
+ /**
+ * This model represents a long running task process
+ */
+ var Task = function( ds, operationType, taskDescription ) {
+ this.taskDescription = taskDescription;
+ this.ds = ds;
+ this.operationType = operationType;
+ this.delay = 500;
+
+ _.bindAll( this, "checkTaskStatus", "onCurrentTaskStatusFail",
"onCurrentTaskStatus" );
+
+ this.checkTaskStatus();
+ };
+
+ _.extend( Task.prototype, {
+ /** Return the unique ID (on this server) of the task */
+ taskId: function() {
+ return this.taskDescription.taskId;
+ },
+
+ /** Return the URL for the task's API */
+ taskURL: function() {
+ return sprintf( "%s/$/tasks/%s", this.ds.baseURL(), this.taskId() );
+ },
+
+ /** Test the current status of the task */
+ checkTaskStatus: function() {
+ $.getJSON( this.taskURL() )
+ .done( this.onCurrentTaskStatus )
+ .fail( this.onCurrentTaskStatusFail )
+ },
+
+ /** Successful result from checking the task */
+ onCurrentTaskStatus: function( taskDescription ) {
+ this.taskDescription = taskDescription;
+
+ var status = {
+ task: this,
+ dsId: this.ds.name(),
+ finished: this.taskFinished()
+ };
+
+ fui.vent.trigger( "task.status", status );
+
+ this.queueTaskStatusCheck();
+ },
+
+ /** Failed to check the task */
+ onCurrentTaskStatusFail: function( jqxhr, msg, err ) {
+ var status = {
+ task: this,
+ dsId: this.ds.name(),
+ errorMessage: err || msg
+ };
+
+ fui.vent.trigger( "task.failed", status );
+ },
+
+ /** Re-queue the status check if the task is not yet complete */
+ queueTaskStatusCheck: function() {
+ if (!this.taskFinished()) {
+ _.delay( this.checkTaskStatus, this.statusDelay() );
+ }
+ },
+
+ /** Return the completion time if the task has been fid, otherwise null
*/
+ taskFinished: function() {
+ return this.taskDescription.finished;
+ },
+
+ /** Return the delay in ms until the next status check is due. */
+ statusDelay: function() {
+ var t = this.delay;
+
+ if (t < MAX_DELAY) {
+ this.delay = t * 2;
+ }
+
+ return t;
+ }
+ } );
+
+ return Task;
+ }
+);
+
Modified:
jena/Experimental/jena-fuseki2/src/main/webapp/js/app/templates/dataset-management.tpl
URL:
http://svn.apache.org/viewvc/jena/Experimental/jena-fuseki2/src/main/webapp/js/app/templates/dataset-management.tpl?rev=1603977&r1=1603976&r2=1603977&view=diff
==============================================================================
---
jena/Experimental/jena-fuseki2/src/main/webapp/js/app/templates/dataset-management.tpl
(original)
+++
jena/Experimental/jena-fuseki2/src/main/webapp/js/app/templates/dataset-management.tpl
Thu Jun 19 17:52:25 2014
@@ -15,9 +15,8 @@
<td><input type='checkbox' class='checkbox' checked /></td>
<td>
<div>
- <a class="btn btn-sm action remove btn-primary"
data-mgmt-uri='<%= ds.mgmtURL() %>' data-ds-id='<%= ds.name() %>'><i class='fa
fa-times-circle'></i> remove</a>
- <a class="btn btn-sm action backup btn-primary" data-uri='<%=
ds.mgmtURL() %>'><i class='fa fa-download'></i> backup</a>
- <a class="btn btn-sm action configure btn-primary"
href="admin-dataset-details.html#<%= ds.name() %>"><i class='fa fa-wrench'></i>
configure</a>
+ <a class="btn btn-sm action remove btn-primary"
data-ds-id='<%= ds.name() %>'><i class='fa fa-times-circle'></i> remove</a>
+ <a class="btn btn-sm action backup btn-primary"
data-ds-id='<%= ds.name() %>'><i class='fa fa-download'></i> backup</a>
<a class="btn btn-sm action add-data btn-primary"
href="dataset.html?tab=upload&ds=<%= ds.name() %>"><i class='fa
fa-plus-circle'></i> add data</a>
</div>
<div class="action feedback"></a>
@@ -32,19 +31,22 @@
<!-- Modal dialogs -->
-<div class="modal fade" id="deleteConfirmModal" tabindex="-1" role="dialog"
aria-labelledby="deleteConfirmModalLabel" aria-hidden="true">
+<div class="modal fade" id="actionConfirmModal" tabindex="-1" role="dialog"
aria-labelledby="actionConfirmModalLabel" aria-hidden="true">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal"
aria-hidden="true">×</button>
- <h4 class="modal-title" id="deleteConfirmModalLabel">Confirm
delete</h4>
+ <h4 class="modal-title" id="actionConfirmModalLabel">Confirm
action</h4>
</div>
<div class="modal-body">
<p></p>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-default" data-dismiss="modal"><i
class="fa fa-icon-remove"></i> Cancel</button>
- <button type="button" class="btn btn-primary action confirm"><i
class="fa fa-icon-confirm"></i> Confirm delete</button>
+ <button type="button" class="btn btn-primary action confirm">
+ <i class="fa fa-icon-confirm"></i>
+ Confirm <span class="action-label">action</span>
+ </button>
</div>
</div><!-- /.modal-content -->
</div><!-- /.modal-dialog -->
Modified:
jena/Experimental/jena-fuseki2/src/main/webapp/js/app/views/dataset-management.js
URL:
http://svn.apache.org/viewvc/jena/Experimental/jena-fuseki2/src/main/webapp/js/app/views/dataset-management.js?rev=1603977&r1=1603976&r2=1603977&view=diff
==============================================================================
---
jena/Experimental/jena-fuseki2/src/main/webapp/js/app/views/dataset-management.js
(original)
+++
jena/Experimental/jena-fuseki2/src/main/webapp/js/app/views/dataset-management.js
Thu Jun 19 17:52:25 2014
@@ -8,23 +8,31 @@ define(
var DataManagementView = Backbone.Marionette.ItemView.extend( {
initialize: function(){
- _.bindAll( this, "onRemoveDataset", "onConfirmRemoveDataset",
- "onDatasetRemoveSuccess", "onDatasetRemoveFail" );
+ _.bindAll( this, "onRemoveDataset", "onConfirmAction",
+ "onDatasetRemoveSuccess", "onDatasetRemoveFail",
+ "onTaskStatus", "onTaskFailed" );
+
this.listenTo( this.model, "change", this.onModelChange, this );
+
+ fui.vent.on( "action.delete.confirm", this.onConfirmRemoveDataset );
+ fui.vent.on( "action.backup.confirm", this.onConfirmBackupDataset );
+
+ fui.vent.on( "task.status", this.onTaskStatus );
+ fui.vent.on( "task.failed", this.onTaskFailed );
},
template: _.template( datasetManagementViewTpl ),
ui: {
+ actionConfirmModal: "#actionConfirmModal"
},
el: "#dataset-management",
events: {
"click .action.remove": "onRemoveDataset",
- "click .action.confirm": "onConfirmRemoveDataset"
-// "change #independent-variable-selection": "selectVariable",
-// "click a.action.filter": "onFilter"
+ "click .action.confirm": "onConfirmAction",
+ "click .action.backup": "onBackupDataset"
},
templateHelpers: {
@@ -33,7 +41,7 @@ define(
/** If the model changes, update the summary */
onModelChange: function( event ) {
-// this.ui.summary.html(
this.model.independentVar().component.range().summarise() );
+ this.render();
},
/** User has requested a dataset be removed */
@@ -41,22 +49,49 @@ define(
e.preventDefault();
var elem = $(e.currentTarget);
var dsId = elem.data( "ds-id" );
- var msg = sprintf( "Are you sure you want to delete dataset %s? This
action cannot be reversed.", dsId );
- var deleteConfirmModal = $( "#deleteConfirmModal" );
+ var msg = sprintf( "Are you sure you want to delete dataset
<code>%s</code>? This action cannot be reversed.", dsId );
- deleteConfirmModal.find( ".modal-body p" ).html( msg );
- deleteConfirmModal.find( ".action.confirm" ).data( "ds-id", dsId );
+ this.showConfirmationModal( msg, dsId, "action.delete.confirm" );
+ },
- this.clearFeedback();
+ /** User has requested a dataset be backed up */
+ onBackupDataset: function( e ) {
+ e.preventDefault();
+ var elem = $(e.currentTarget);
+ var dsId = elem.data( "ds-id" );
+ var msg = sprintf( "Are you sure you want to create a backup of
dataset <code>%s</code>? This action may take some time to complete", dsId );
- deleteConfirmModal.modal( 'show' );
+ this.showConfirmationModal( msg, dsId, "action.backup.confirm" );
},
- /** User has confirmed that the dataset can be deleted */
- onConfirmRemoveDataset: function( e ) {
+ /** Show a generic modal confirmation */
+ showConfirmationModal: function( msg, dsId, eventId ) {
+ this.ui.actionConfirmModal
+ .find( ".modal-body p" )
+ .html( msg );
+
+ this.ui.actionConfirmModal
+ .find( ".action.confirm" )
+ .data( "ds-id", dsId )
+ .data( "event-id", eventId );
+
+ this.clearFeedback();
+ this.ui.actionConfirmModal.modal( 'show' );
+ },
+
+ /** Generic response to confirming the current modal dialogue */
+ onConfirmAction: function( e ) {
e.preventDefault();
var elem = $(e.currentTarget);
var dsId = elem.data( "ds-id" );
+ var eventId = elem.data( "event-id" );
+
+ fui.vent.trigger( eventId, dsId );
+ this.ui.actionConfirmModal.modal( 'hide' );
+ },
+
+ /** User has confirmed that the dataset can be deleted */
+ onConfirmRemoveDataset: function( dsId ) {
var self = this;
fui.models
@@ -65,8 +100,6 @@ define(
.deleteDataset()
.done( function( data ) {self.onDatasetRemoveSuccess( data, dsId
);} )
.error( function( jqxhr, msg, err ) {self.onDatasetRemoveFail(
jqxhr, msg, err, dsId );} );
-
- $( "#deleteConfirmModal" ).modal( 'hide' );
},
onDatasetRemoveSuccess: function( data, dsId ) {
@@ -75,15 +108,48 @@ define(
/** Removing the dataset did not work: notify the user */
onDatasetRemoveFail: function( jqxhr, msg, err, dsId ) {
- $(sprintf( ".action.remove[data-ds-id='%s']", dsId ) )
- .parent()
- .siblings(".action.feedback")
- .html( sprintf( "<p class='text-warning'>Sorry, removing dataset %s
did not work, because: '%s'</p>", dsId, err || msg ) );
+ this.feedbackArea( dsId )
+ .html( sprintf( "<p class='text-warning'>Sorry, removing dataset
%s did not work, because: '%s'</p>", dsId, err || msg ) );
+ },
+
+ /** User has confirmed backing up the dataset */
+ onConfirmBackupDataset: function( dsId ) {
+ var self = this;
+
+ fui.models
+ .fusekiServer
+ .dataset( dsId )
+ .backupDataset();
},
/** Remove any current feedback content */
clearFeedback: function() {
$(".action.feedback").empty();
+ },
+
+ /** Long running task has updated status */
+ onTaskStatus: function( status ) {
+ var task = status.task;
+ var msg = sprintf( "<p>Task <strong>%s</strong> started at %s%s</p>",
+ task.operationType,
+ task.taskDescription.started,
+ status.finished ? sprintf( ", finished at %s",
status.finished ) : " – ongoing" );
+
+ this.feedbackArea( status.dsId )
+ .html( msg );
+ },
+
+ /** Long running task has failed to start */
+ onTaskFailed: function( status ) {
+ this.feedbackArea( status.dsId )
+ .html( sprintf( "<p class='text-danger'>Task %s failed: '%s'</p>",
task.operationType, task.errorMessage ));
+ },
+
+ /** Find the feedback area for a particular dataset */
+ feedbackArea: function( dsId ) {
+ return $(sprintf( ".action[data-ds-id='%s']", dsId ) )
+ .parent()
+ .siblings(".action.feedback");
}
});