jenkins-bot has submitted this change and it was merged.

Change subject: Added deferred actions
......................................................................


Added deferred actions

The "deferred actions" components make it easier to create batch
processing tasks with asynchronous behavior. It features some MW API
default actions and a dialog/panel to visualize the progress.

PatchSet 1:
* Fixed syntax error

PatchSet 2:
* Added QQQ file for i18n
* Implemented comments by Siebrand/Raimond
* Added resource module for i18n

Change-Id: I7736553699b09f441cb775e08532d4eaa3da036a
---
M BlueSpiceFoundation.php
A i18n/deferred/de.json
A i18n/deferred/en.json
A i18n/deferred/qqq.json
M i18n/extjs/de.json
M i18n/extjs/en.json
M i18n/extjs/qqq.json
A languages/BlueSpice.Deferred.i18n.php
M resources/Resources.php
A resources/bluespice.extjs/BS/action/APICopyPage.js
A resources/bluespice.extjs/BS/action/APIEditPage.js
A resources/bluespice.extjs/BS/action/Base.js
A resources/bluespice.extjs/BS/dialog/BatchActions.js
A resources/bluespice.extjs/BS/panel/BatchActions.js
14 files changed, 433 insertions(+), 0 deletions(-)

Approvals:
  Robert Vogel: Looks good to me, approved
  Siebrand: Looks good to me, but someone else must approve
  Raimond Spekking: Looks good to me, but someone else must approve
  jenkins-bot: Verified



diff --git a/BlueSpiceFoundation.php b/BlueSpiceFoundation.php
index 3b8e5e6..f7d8e79 100644
--- a/BlueSpiceFoundation.php
+++ b/BlueSpiceFoundation.php
@@ -73,6 +73,7 @@
 $wgMessagesDirs['BlueSpiceDiagnostics'] = __DIR__ . '/i18n/diagnostics';
 $wgMessagesDirs['BlueSpice.ExtJS'] = __DIR__ . '/i18n/extjs';
 $wgMessagesDirs['BlueSpice.ExtJS.Portal'] = __DIR__ . '/i18n/extjs-portal';
+$wgMessagesDirs['BlueSpice.Deferred'] = __DIR__ . '/i18n/deferred';
 $wgMessagesDirs['Validator'] = __DIR__ . '/i18n/validator';
 
 //I18N Backwards compatibility
@@ -81,6 +82,7 @@
        'Validator' => __DIR__."/languages/Validator.i18n.php",
        'BlueSpice.ExtJS' => __DIR__."/languages/BlueSpice.ExtJS.i18n.php",
        'BlueSpice.ExtJS.Portal' => 
__DIR__."/languages/BlueSpice.ExtJS.Portal.i18n.php",
+       'BlueSpice.Deferred' => 
__DIR__.'/languages/BlueSpice.Deferred.i18n.php',
        'BlueSpiceDiagnostics' => 
__DIR__."/languages/BlueSpice.Diagnostics.i18n.php",
        'DiagnosticsAlias' => 
__DIR__."/languages/BlueSpice.Diagnostics.alias.php",
        'BlueSpiceCredits' => __DIR__."/languages/BlueSpice.Credits.i18n.php",
diff --git a/i18n/deferred/de.json b/i18n/deferred/de.json
new file mode 100644
index 0000000..6cfe7cb
--- /dev/null
+++ b/i18n/deferred/de.json
@@ -0,0 +1,18 @@
+{
+       "@metadata": {
+               "authors": [
+                       "Robert Vogel <vo...@hallowelt.biz>"
+               ]
+       },
+       "bs-deferred-action-status-pending": "Warten.",
+       "bs-deferred-action-status-running": "Läuft...",
+       "bs-deferred-action-status-done": "Abgeschloßen.",
+       "bs-deferred-action-status-error": "Fehlgeschlagen.",
+       "bs-deferred-action-apicopypage-description": "Kopieren von \"$1\" nach 
\"$2\".",
+       "bs-deferred-action-apieditpage-description": "Bearbeiten von \"$1\".",
+       "bs-deferred-batch-title": "Stapelverarbeitung",
+       "bs-deferred-batch-progress-desc": "Fortschritt",
+       "bs-deferred-batch-actions": "Aktionen",
+       "bs-deferred-batch-description": "Beschreibung",
+       "bs-deferred-batch-status": "Status"
+}
diff --git a/i18n/deferred/en.json b/i18n/deferred/en.json
new file mode 100644
index 0000000..e26d86b
--- /dev/null
+++ b/i18n/deferred/en.json
@@ -0,0 +1,18 @@
+{
+       "@metadata": {
+               "authors": [
+                       "Robert Vogel <vo...@hallowelt.biz>"
+               ]
+       },
+       "bs-deferred-action-status-pending": "Pending.",
+       "bs-deferred-action-status-running": "Running...",
+       "bs-deferred-action-status-done": "Done.",
+       "bs-deferred-action-status-error": "Failed.",
+       "bs-deferred-action-apicopypage-description": "Copy \"$1\" to \"$2\".",
+       "bs-deferred-action-apieditpage-description": "Edit \"$1\".",
+       "bs-deferred-batch-title": "Batch processing",
+       "bs-deferred-batch-progress-desc": "Progress",
+       "bs-deferred-batch-actions": "Actions",
+       "bs-deferred-batch-description": "Description",
+       "bs-deferred-batch-status": "Status"
+}
diff --git a/i18n/deferred/qqq.json b/i18n/deferred/qqq.json
new file mode 100644
index 0000000..52ba7b5
--- /dev/null
+++ b/i18n/deferred/qqq.json
@@ -0,0 +1,18 @@
+{
+       "@metadata": {
+               "authors": [
+                       "Robert Vogel <vo...@hallowelt.biz>"
+               ]
+       },
+       "bs-deferred-action-status-pending": "Value of a cell in an overview 
table that tells that a particular action has not started yet",
+       "bs-deferred-action-status-running": "Value of a cell in an overview 
table that tells that a particular action has started",
+       "bs-deferred-action-status-done": "Value of a cell in an overview table 
that tells that a particular action has been completed without errors",
+       "bs-deferred-action-status-error": "Value of a cell in an overview 
table that tells that a particular action has failed during execution",
+       "bs-deferred-action-apicopypage-description": "Description of an action 
that copies the content of a page to another one.\n\nParameters:\n* $1 - The 
source page title to be copied from\n* $2 - The target page title to be copied 
to",
+       "bs-deferred-action-apieditpage-description": "Description of an action 
that edits the contents of a page.\n\nParameters:\n* $1 - The title of the page 
that will be edited",
+       "bs-deferred-batch-title": "Title of a dialog or panel that shows a 
list of actions to be processed",
+       "bs-deferred-batch-progress-desc": "Title of a fieldset that displays 
the progress of the running batch process",
+       "bs-deferred-batch-actions": "Title of the column that shows the names 
of the actions on the batch",
+       "bs-deferred-batch-description": "Title of the column that shows a 
short description of the actions on the batch",
+       "bs-deferred-batch-status": "Title of the column that shows the current 
state of the actions on the batch"
+}
diff --git a/i18n/extjs/de.json b/i18n/extjs/de.json
index f2e3570..d649306 100644
--- a/i18n/extjs/de.json
+++ b/i18n/extjs/de.json
@@ -13,6 +13,7 @@
        "bs-extjs-add": "Hinzufügen",
        "bs-extjs-remove": "Entfernen",
        "bs-extjs-edit": "Bearbeiten",
+       "bs-extjs-copy": "Kopieren",
        "bs-extjs-hint": "Hinweis",
        "bs-extjs-error": "Fehler",
        "bs-extjs-confirm": "Bestätigen",
diff --git a/i18n/extjs/en.json b/i18n/extjs/en.json
index feae8f8..80ddaf3 100644
--- a/i18n/extjs/en.json
+++ b/i18n/extjs/en.json
@@ -13,6 +13,7 @@
        "bs-extjs-add": "Add",
        "bs-extjs-remove": "Remove",
        "bs-extjs-edit": "Edit",
+       "bs-extjs-copy": "Copy",
        "bs-extjs-hint": "Hint",
        "bs-extjs-error": "Error",
        "bs-extjs-confirm": "Confirm",
diff --git a/i18n/extjs/qqq.json b/i18n/extjs/qqq.json
index 36e7470..5ea4264 100644
--- a/i18n/extjs/qqq.json
+++ b/i18n/extjs/qqq.json
@@ -16,6 +16,7 @@
        "bs-extjs-add": "{{Identical|Add}}",
        "bs-extjs-remove": "{{Identical|Remove}}",
        "bs-extjs-edit": "{{Identical|Edit}}",
+       "bs-extjs-copy": "Label for copy action controls used in dialogues, 
alerts and prompts.\n{{Identical|Copy}}",
        "bs-extjs-hint": "Title for hint prompts.\n{{Identical|Hint}}",
        "bs-extjs-error": "Title for error prompts.\n{{Identical|Error}}",
        "bs-extjs-confirm": "Title for confirm prompts\n{{Identical|Confirm}}",
diff --git a/languages/BlueSpice.Deferred.i18n.php 
b/languages/BlueSpice.Deferred.i18n.php
new file mode 100644
index 0000000..c45b02f
--- /dev/null
+++ b/languages/BlueSpice.Deferred.i18n.php
@@ -0,0 +1,35 @@
+<?php
+/**
+ * This is a backwards-compatibility shim, generated by:
+ * 
https://git.wikimedia.org/blob/mediawiki%2Fcore.git/HEAD/maintenance%2FgenerateJsonI18n.php
+ *
+ * Beginning with MediaWiki 1.23, translation strings are stored in json files,
+ * and the EXTENSION.i18n.php file only exists to provide compatibility with
+ * older releases of MediaWiki. For more information about this migration, see:
+ * https://www.mediawiki.org/wiki/Requests_for_comment/Localisation_format
+ *
+ * This shim maintains compatibility back to MediaWiki 1.17.
+ */
+$messages = array();
+if ( !function_exists( 'wfJsonBSDEFERRED' ) ) {
+       function wfJsonBSDEFERRED( $cache, $code, &$cachedData ) {
+               $codeSequence = array_merge( array( $code ), 
$cachedData['fallbackSequence'] );
+               foreach ( $codeSequence as $csCode ) {
+                       $fileName = dirname( __FILE__ ) . 
"/../i18n/deferred/$csCode.json";
+                       if ( is_readable( $fileName ) ) {
+                               $data = FormatJson::decode( file_get_contents( 
$fileName ), true );
+                               foreach ( array_keys( $data ) as $key ) {
+                                       if ( $key === '' || $key[0] === '@' ) {
+                                               unset( $data[$key] );
+                                       }
+                               }
+                               $cachedData['messages'] = array_merge( $data, 
$cachedData['messages'] );
+                       }
+
+                       $cachedData['deps'][] = new FileDependency( $fileName );
+               }
+               return true;
+       }
+
+       $GLOBALS['wgHooks']['LocalisationCacheRecache'][] = 'wfJsonBSDEFERRED';
+}
diff --git a/resources/Resources.php b/resources/Resources.php
index 74be6b7..346589c 100644
--- a/resources/Resources.php
+++ b/resources/Resources.php
@@ -78,6 +78,7 @@
                'bs-extjs-edit',
                'bs-extjs-add',
                'bs-extjs-remove',
+               'bs-extjs-copy',
                'bs-extjs-hint',
                'bs-extjs-error',
                'bs-extjs-confirm',
@@ -142,6 +143,25 @@
        )
 ) + $aResourceModuleTemplate;
 
+$wgResourceModules['ext.bluespice.extjs.BS.deferred'] = array(
+       'dependencies' => array(
+               'ext.bluespice.extjs'
+       ),
+       'messages' => array(
+               'bs-deferred-action-status-pending',
+               'bs-deferred-action-status-running',
+               'bs-deferred-action-status-done',
+               'bs-deferred-action-status-error',
+               'bs-deferred-action-apicopypage-description',
+               'bs-deferred-action-apieditpage-description',
+               'bs-deferred-batch-title',
+               'bs-deferred-batch-progress-desc',
+               'bs-deferred-batch-actions',
+               'bs-deferred-batch-description',
+               'bs-deferred-batch-status'
+       )
+) + $aResourceModuleTemplate;
+
 $wgResourceModules['ext.bluespice.extjs.BS.portal.css'] = array(
        'styles' => array(
                'bluespice.extjs/bluespice.extjs.BS.portal.css'
diff --git a/resources/bluespice.extjs/BS/action/APICopyPage.js 
b/resources/bluespice.extjs/BS/action/APICopyPage.js
new file mode 100644
index 0000000..80663a3
--- /dev/null
+++ b/resources/bluespice.extjs/BS/action/APICopyPage.js
@@ -0,0 +1,53 @@
+Ext.define('BS.action.APICopyPage', {
+       extend: 'BS.action.APIEditPage',
+
+       //Custom Settings
+       sourceTitle: '',
+       targetTitle: '',
+
+       execute: function() {
+               var me = this;
+               var dfd = $.Deferred();
+               this.actionStatus = BS.action.Base.STATUS_RUNNING;
+               var copy = {
+                       sourceTitle: me.sourceTitle,
+                       targetTitle: me.targetTitle
+               };
+
+               var getCurrentTextAPI = new mw.Api();
+                       getCurrentTextAPI.get({
+                               action: 'query',
+                               titles: this.sourceTitle,
+                               prop: 'revisions',
+                               rvprop: 'content',
+                               indexpageids : ''
+                       })
+                       .fail(function( code, errResp ){
+                               me.actionStatus = BS.action.Base.STATUS_ERROR;
+                               dfd.reject( me, copy, errResp );
+                       })
+                       .done(function( resp, jqXHR ){
+                               var pageId = resp.query.pageids[0];
+                               var pageInfo = resp.query.pages[pageId];
+                               if( pageInfo.missing || !pageInfo.revisions || 
!pageInfo.revisions[0] ) {
+                                       me.actionStatus = 
BS.action.Base.STATUS_ERROR;
+                                       dfd.reject( me, copy, resp );
+                                       return;
+                               }
+                               me.pageTitle = me.targetTitle;
+                               me.pageContent = pageInfo.revisions[0]['*'];
+                               var basePromise = me.superclass.execute.apply( 
me );
+                               basePromise.fail(function() {
+                                       dfd.reject.apply( dfd, arguments );
+                               }).done( function() {
+                                       dfd.resolve.apply( dfd, arguments );
+                               });
+                       });
+
+               return dfd.promise();
+       },
+
+       getDescription: function() {
+               return mw.message('bs-deferred-action-apicopypage-description', 
this.sourceTitle, this.targetTitle).parse();
+       }
+});
\ No newline at end of file
diff --git a/resources/bluespice.extjs/BS/action/APIEditPage.js 
b/resources/bluespice.extjs/BS/action/APIEditPage.js
new file mode 100644
index 0000000..6345c9d
--- /dev/null
+++ b/resources/bluespice.extjs/BS/action/APIEditPage.js
@@ -0,0 +1,63 @@
+Ext.define('BS.action.APIEditPage', {
+       extend: 'BS.action.Base',
+
+       //Custom config
+       pageTitle: '',
+       pageContent: '',
+
+       constructor: function( cfg ) {
+               this.addEvents( 'beforesaveedit' );
+               this.callParent(arguments);
+       },
+
+       execute: function() {
+               var dfd = $.Deferred();
+               this.actionStatus = BS.action.Base.STATUS_RUNNING;
+
+               var edit = {
+                       title: this.pageTitle,
+                       content: this.pageContent
+               };
+
+               this.doAPIEdit( dfd, edit );
+
+               return dfd.promise();
+       },
+
+       doAPIEdit: function( dfd, edit ) {
+               var me = this;
+               this.fireEvent( 'beforesaveedit', this, edit );
+
+               var editPageAPI = new mw.Api();
+               editPageAPI.postWithToken( 'edit', {
+                       'action': 'edit',
+                       'title': edit.title,
+                       'text': edit.content,
+                       'continue': ''
+               })
+               .fail(function( code, errResp ){
+                       me.actionStatus = BS.action.Base.STATUS_ERROR;
+                       dfd.reject( me, edit, errResp );
+               })
+               .done(function( resp, jqXHR ){
+                       if( !resp.edit.result || resp.edit.result.toLowerCase() 
!== 'success' ) {
+                               me.actionStatus = BS.action.Base.STATUS_ERROR;
+                               dfd.reject( me, edit, resp );
+                               return;
+                       }
+
+                       if( resp.edit.title === undefined ) {
+                               me.actionStatus = BS.action.Base.STATUS_ERROR;
+                               dfd.reject( me, edit, resp );
+                               return;
+                       }
+
+                       me.actionStatus = BS.action.Base.STATUS_DONE;
+                       dfd.resolve( me );
+               });
+       },
+
+       getDescription: function() {
+               return mw.message('bs-deferred-action-apieditpage-description', 
this.pageTitle).parse();
+       }
+});
\ No newline at end of file
diff --git a/resources/bluespice.extjs/BS/action/Base.js 
b/resources/bluespice.extjs/BS/action/Base.js
new file mode 100644
index 0000000..2f39fce
--- /dev/null
+++ b/resources/bluespice.extjs/BS/action/Base.js
@@ -0,0 +1,43 @@
+Ext.define( 'BS.action.Base', {
+       extend: 'Ext.util.Observable',
+       statics: {
+               STATUS_ERROR: -1,
+               STATUS_PENDING: 0,
+               STATUS_RUNNING: 1,
+               STATUS_DONE: 2
+       },
+
+       actionStatus: 0, //BS.action.Base.STATUS_PENDING
+
+       /**
+        *
+        * @returns jQuery.Promise
+        */
+       execute: function() {
+
+       },
+
+       getDescription: function() {
+               return Ext.getClassName( this );
+       },
+
+       getStatus: function() {
+               return this.actionStatus;
+       },
+
+       getStatusText: function() {
+               var status = this.getStatus();
+               var message = '';
+               if( status === BS.action.Base.STATUS_PENDING ) {
+                       message = 
mw.message('bs-deferred-action-status-pending').plain();
+               } else if( status === BS.action.Base.STATUS_RUNNING ) {
+                       message = 
mw.message('bs-deferred-action-status-running').plain();
+               } else if( status === BS.action.Base.STATUS_DONE ) {
+                       message = 
mw.message('bs-deferred-action-status-done').plain();
+               } else if( status === BS.action.Base.STATUS_ERROR ) {
+                       message = 
mw.message('bs-deferred-action-status-error').plain();
+               }
+
+               return message;
+       }
+});
\ No newline at end of file
diff --git a/resources/bluespice.extjs/BS/dialog/BatchActions.js 
b/resources/bluespice.extjs/BS/dialog/BatchActions.js
new file mode 100644
index 0000000..3db6675
--- /dev/null
+++ b/resources/bluespice.extjs/BS/dialog/BatchActions.js
@@ -0,0 +1,45 @@
+Ext.define( 'BS.dialog.BatchActions', {
+       extend: 'BS.Window',
+       requires: [ 'BS.panel.BatchActions' ],
+
+       width: 600,
+       autoHeight: true,
+       title: mw.message('bs-deferred-batch-title').plain(),
+       closable: false,
+
+       afterInitComponent: function() {
+               this.pnlBatchActions = new BS.panel.BatchActions();
+               this.pnlBatchActions.on( 'processcomplete', 
this.onProcessComplete, this );
+
+               this.items = [
+                       this.pnlBatchActions
+               ];
+
+               this.btnCancel.hide();
+
+               this.callParent( arguments );
+       },
+
+       setData: function( data ) {
+               this.pnlBatchActions.setData( data );
+               this.callParent( arguments );
+       },
+
+       onBtnOKClick: function() {
+               if( this.pnlBatchActions.isProcessComplete() ) {
+                       this.callParent( arguments );
+               }
+               else {
+                       this.startProcessing();
+               }
+       },
+
+       onProcessComplete: function() {
+               this.btnOK.enable();
+       },
+
+       startProcessing: function() {
+               this.btnOK.disable();
+               this.pnlBatchActions.startProcessing();
+       }
+});
\ No newline at end of file
diff --git a/resources/bluespice.extjs/BS/panel/BatchActions.js 
b/resources/bluespice.extjs/BS/panel/BatchActions.js
new file mode 100644
index 0000000..9360ae5
--- /dev/null
+++ b/resources/bluespice.extjs/BS/panel/BatchActions.js
@@ -0,0 +1,115 @@
+Ext.define( 'BS.panel.BatchActions', {
+       extend: 'Ext.Panel',
+
+       initComponent: function() {
+               this.pbActions = new Ext.ProgressBar({
+                       width: '100%'
+               });
+
+               this.gdActions = new Ext.grid.Panel({
+                       height: 200,
+                       viewConfig:{
+                               markDirty: false
+                       },
+                       columns: {
+                               items: [
+                                       {
+                                               text: 
mw.message('bs-deferred-batch-description').plain(),
+                                               dataIndex: 'description',
+                                               flex: 1
+                                       },
+                                       {
+                                               text: 
mw.message('bs-deferred-batch-status').plain(),
+                                               dataIndex: 'state',
+                                               width: 120
+                                       }
+                               ]
+                       },
+                       store: new Ext.data.JsonStore({
+                               fields: ['description', 'state' ]
+                       })
+               });
+
+               this.fsActions = new Ext.form.FieldSet({
+                       title: mw.message('bs-deferred-batch-actions').plain(),
+                       collapsible:true,
+                       collapsed: true,
+                       items: [
+                               this.gdActions
+                       ]
+               });
+
+               this.items = [
+                       {
+                               html: 
mw.message('bs-deferred-batch-progress-desc').plain()
+                       },
+                       this.pbActions,
+                       this.fsActions
+               ];
+
+               this.addEvents( 'processtart', 'processcomplete', 
'actioncomplete' );
+
+               this.callParent( arguments );
+       },
+
+       currrentActions: [],
+       setData: function( data ) {
+               this.currentActions = data;
+               var storeData = [];
+               for( var i = 0; i < data.length; i++ ) {
+
+                       storeData.push({
+                               description: data[i].getDescription(),
+                               state: data[i].getStatusText()
+                       });
+               }
+
+               this.gdActions.getStore().loadData( storeData );
+               this.processComplete = false;
+               this.pbActions.updateProgress( 0, '0%' );
+       },
+
+       startProcessing: function() {
+               this.fireEvent( 'processtart', this );
+               this.processAction( 0 );
+       },
+
+       processComplete: false,
+       processAction: function( index ) {
+               if( index >= this.currentActions.length ) { //End of chain
+                       this.processComplete = true;
+                       this.fireEvent( 'processcomplete', this );
+                       return;
+               }
+               if( !this.currentActions[index] ) {
+                       return;
+               }
+               var me = this;
+               var promise = this.currentActions[index].execute();
+               var record = me.gdActions.getStore().getAt( index );
+               record.set( 'state', me.currentActions[index].getStatusText() );
+               promise.done(function() {
+                       me.actionComplete( index, record );
+               })
+               .fail(function() {
+                       me.fsActions.expand();
+                       //TODO: Show prompt and hold process? Or error report 
after process?
+                       me.actionComplete( index, record );
+               });
+       },
+
+       isProcessComplete: function() {
+               return this.processComplete;
+       },
+
+       actionComplete: function( index, record ) {
+               record.set( 'state', this.currentActions[index].getStatusText() 
);
+               var progress = (index + 1) / this.currentActions.length;
+               this.fireEvent( 'actioncomplete', this, progress );
+               this.pbActions.updateProgress(
+                       progress,
+                       Math.ceil(progress * 100) + '%'
+               );
+               this.processAction( index + 1 );
+       }
+});
\ No newline at end of file

-- 
To view, visit https://gerrit.wikimedia.org/r/211665
To unsubscribe, visit https://gerrit.wikimedia.org/r/settings

Gerrit-MessageType: merged
Gerrit-Change-Id: I7736553699b09f441cb775e08532d4eaa3da036a
Gerrit-PatchSet: 4
Gerrit-Project: mediawiki/extensions/BlueSpiceFoundation
Gerrit-Branch: master
Gerrit-Owner: Robert Vogel <vo...@hallowelt.biz>
Gerrit-Reviewer: Mglaser <gla...@hallowelt.biz>
Gerrit-Reviewer: Pwirth <wi...@hallowelt.biz>
Gerrit-Reviewer: Raimond Spekking <raimond.spekk...@gmail.com>
Gerrit-Reviewer: Robert Vogel <vo...@hallowelt.biz>
Gerrit-Reviewer: Siebrand <siebr...@kitano.nl>
Gerrit-Reviewer: Tweichart <weich...@hallowelt.biz>
Gerrit-Reviewer: jenkins-bot <>

_______________________________________________
MediaWiki-commits mailing list
MediaWiki-commits@lists.wikimedia.org
https://lists.wikimedia.org/mailman/listinfo/mediawiki-commits

Reply via email to