Robert Vogel has uploaded a new change for review. https://gerrit.wikimedia.org/r/211665
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 an dialog/panel to visualize the progress. Change-Id: I7736553699b09f441cb775e08532d4eaa3da036a --- M BlueSpiceFoundation.php A i18n/deferred/de.json A i18n/deferred/en.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 13 files changed, 396 insertions(+), 0 deletions(-) git pull ssh://gerrit.wikimedia.org:29418/mediawiki/extensions/BlueSpiceFoundation refs/changes/65/211665/1 diff --git a/BlueSpiceFoundation.php b/BlueSpiceFoundation.php index 3b8e5e6..529f338 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..96e19b5 --- /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..014df0f --- /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/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..2c559ad 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', 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: newchange Gerrit-Change-Id: I7736553699b09f441cb775e08532d4eaa3da036a Gerrit-PatchSet: 1 Gerrit-Project: mediawiki/extensions/BlueSpiceFoundation Gerrit-Branch: master Gerrit-Owner: Robert Vogel <vo...@hallowelt.biz> _______________________________________________ MediaWiki-commits mailing list MediaWiki-commits@lists.wikimedia.org https://lists.wikimedia.org/mailman/listinfo/mediawiki-commits