Santhosh has uploaded a new change for review.

  https://gerrit.wikimedia.org/r/270256

Change subject: Show basic user stats in the translation dashboard
......................................................................

Show basic user stats in the translation dashboard

Bug: T111776
Change-Id: I4b4edee1d2031417e51a42077c206d889373d29d
---
M api/ApiQueryContentTranslationLanguageTrend.php
A api/ApiQueryTranslatorStats.php
M extension.json
M i18n/api/en.json
M i18n/api/qqq.json
M i18n/en.json
M i18n/qqq.json
M includes/Translation.php
M modules/dashboard/ext.cx.dashboard.js
A modules/widgets/translator/ext.cx.translator.js
A modules/widgets/translator/ext.cx.translator.less
A modules/widgets/translator/images/user-small.png
A modules/widgets/translator/images/user-small.svg
13 files changed, 250 insertions(+), 10 deletions(-)


  git pull 
ssh://gerrit.wikimedia.org:29418/mediawiki/extensions/ContentTranslation 
refs/changes/56/270256/1

diff --git a/api/ApiQueryContentTranslationLanguageTrend.php 
b/api/ApiQueryContentTranslationLanguageTrend.php
index 96572a3..1fdae20 100644
--- a/api/ApiQueryContentTranslationLanguageTrend.php
+++ b/api/ApiQueryContentTranslationLanguageTrend.php
@@ -33,8 +33,10 @@
                $interval = $params['interval'];
 
                $data = array(
-                       'translations' => Translation::getTrendByStatus( 
$source, $target, 'published', $interval ),
-                       'drafts' => Translation::getTrendByStatus( $source, 
$target, 'draft', $interval ),
+                       'translations' => Translation::getTrendByStatus(
+                               $source, $target, 'published', $interval, null
+                       ),
+                       'drafts' => Translation::getTrendByStatus( $source, 
$target, 'draft', $interval, null ),
                );
 
                if ( $target !== null ) {
diff --git a/api/ApiQueryTranslatorStats.php b/api/ApiQueryTranslatorStats.php
new file mode 100644
index 0000000..e9c3fc6
--- /dev/null
+++ b/api/ApiQueryTranslatorStats.php
@@ -0,0 +1,64 @@
+<?php
+/**
+ * Api module for querying translation statistics for a translator.
+ *
+ * @file
+ * @copyright See AUTHORS.txt
+ * @license GPL-2.0+
+ */
+
+use ContentTranslation\Translation;
+use ContentTranslation\Translator;
+
+/**
+ * @ingroup API ContentTranslationAPI
+ */
+class ApiQueryTranslatorStats extends ApiQueryBase {
+
+       public function __construct( $query, $moduleName ) {
+               parent::__construct( $query, $moduleName );
+       }
+
+       public function execute() {
+               $result = $this->getResult();
+               $params = $this->extractRequestParams();
+               $user = $this->getUser();
+               if ( isset( $params['translator'] ) ) {
+                       $user = \User::newFromName( $params['translator'] );
+               }
+               $translator = new Translator( $user );
+               $translatorId =  $translator->getGlobalUserId();
+               if ( !$translatorId ) {
+                       $this->dieUsage( 'Invalid translator name', 
'invalidtranslator' );
+               }
+               $publishedStats = Translation::getTrendByStatus(
+                       null, null, 'published', 'month', $translatorId
+               );
+               // TODO: The $publishedStats does not contain data for all 
months,
+               // if there is not translation in that month. 
ApiQueryContentTranslationLanguageTrend
+               // has utility methods to fill it. But it is not important for 
the graph we render
+               // from the output of this data.
+               $result = array(
+                       'translator' => $user->getName(),
+                       'translatorId' => $translatorId,
+                       'publishTrend' => $publishedStats,
+               );
+               $this->getResult()->addValue( null, $this->getModuleName(), 
$result );
+       }
+
+       public function getAllowedParams() {
+               $allowedParams = array(
+                       'translator' => array(
+                               ApiBase::PARAM_TYPE => 'string',
+                       )
+               );
+               return $allowedParams;
+       }
+
+       protected function getExamplesMessages() {
+               return array(
+                       
'action=query&list=cxtranslatorstats&translator=TranslatorName' =>
+                               'apihelp-query+cxtranslatorstats-example-1',
+               );
+       }
+}
diff --git a/extension.json b/extension.json
index 8a15cd1..c7804b0 100644
--- a/extension.json
+++ b/extension.json
@@ -47,7 +47,8 @@
                "contenttranslationlangtrend": 
"ApiQueryContentTranslationLanguageTrend",
                "contenttranslationstats": "ApiQueryContentTranslationStats",
                "contenttranslationsuggestions": 
"ApiQueryContentTranslationSuggestions",
-               "cxpublishedtranslations": "ApiQueryPublishedTranslations"
+               "cxpublishedtranslations": "ApiQueryPublishedTranslations",
+               "cxtranslatorstats": "ApiQueryTranslatorStats"
        },
        "MessagesDirs": {
                "ContentTranslation": "i18n",
@@ -70,6 +71,7 @@
                "ApiQueryContentTranslationLanguageTrend": 
"api/ApiQueryContentTranslationLanguageTrend.php",
                "ApiQueryContentTranslationStats": 
"api/ApiQueryContentTranslationStats.php",
                "ApiQueryPublishedTranslations": 
"api/ApiQueryPublishedTranslations.php",
+               "ApiQueryTranslatorStats": "api/ApiQueryTranslatorStats.php",
                "ContentTranslationHooks": "ContentTranslation.hooks.php",
                "ContentTranslation\\AbuseFilterCheck": 
"includes/AbuseFilterCheck.php",
                "ContentTranslation\\CorporaLookup": 
"includes/CorporaLookup.php",
@@ -265,6 +267,7 @@
                                "ext.cx.source.selector",
                                "ext.cx.suggestionlist",
                                "ext.cx.translationlist",
+                               "ext.cx.widgets.translator",
                                "ext.uls.mediawiki",
                                "mediawiki.Uri",
                                "mediawiki.storage",
@@ -1063,6 +1066,22 @@
                        "styles": [
                                "widgets/callout/ext.cx.callout.css"
                        ]
+               },
+               "ext.cx.widgets.translator": {
+                       "scripts": [
+                               "widgets/translator/ext.cx.translator.js"
+                       ],
+                       "styles": [
+                               "widgets/translator/ext.cx.translator.less"
+                       ],
+                       "messages":[
+                               "cx-translator-month-stats-label",
+                               "cx-translator-total-translations-label"
+                       ],
+                       "dependencies": [
+                               "chart.js",
+                               "mediawiki.api"
+                       ]
                }
        },
        "ResourceFileModulePaths": {
diff --git a/i18n/api/en.json b/i18n/api/en.json
index c93edc6..6518875 100644
--- a/i18n/api/en.json
+++ b/i18n/api/en.json
@@ -82,5 +82,8 @@
        "apihelp-cxsave-description": "This module allows to save draft 
translations by section to save bandwidth and to collect parallel corpora.",
        "apihelp-cxsave-example-1": "Save the source and translation sections. 
The content must be JSON-encoded string.",
        "apihelp-cxsave-param-translationid": "The translation ID",
-       "apihelp-cxsave-param-content": "JSON-encoded section data. Each 
section is an object and has the following keys: content, sectionId, 
sequenceId, sequenceId, origin"
+       "apihelp-cxsave-param-content": "JSON-encoded section data. Each 
section is an object and has the following keys: content, sectionId, 
sequenceId, sequenceId, origin",
+       "apihelp-cxtranslatorstats-description": "Fetch the translation 
statistics for the given user.",
+       "apihelp-cxtranslatorstats-param-translator": "The translators user 
name. This param is optional. If not possed, the current logged-in user will be 
used.",
+       "apihelp-cxtranslatorstats-example-1": "Fetch the translation 
statistics for the given user.",
 }
diff --git a/i18n/api/qqq.json b/i18n/api/qqq.json
index e47dfbf..684cf7e 100644
--- a/i18n/api/qqq.json
+++ b/i18n/api/qqq.json
@@ -78,5 +78,8 @@
        "apihelp-cxsave-description": 
"{{doc-apihelp-description|cxsave}}\n\nFor an explanation of \"parallel 
corpora\" see [[:w:en:Parallel text|Parallel text]].",
        "apihelp-cxsave-example-1": "{{doc-apihelp-example|cxsave}}",
        "apihelp-cxsave-param-translationid": 
"{{doc-apihelp-param|cxsave|translationId}}",
-       "apihelp-cxsave-param-content": "{{doc-apihelp-param|cxsave|content}}"
+       "apihelp-cxsave-param-content": "{{doc-apihelp-param|cxsave|content}}",
+       "apihelp-cxtranslatorstats-description": 
"{{doc-apihelp-description|cxtranslatorstats}}",
+       "apihelp-cxtranslatorstats-param-translator": 
"{{doc-apihelp-param|cxtranslatorstats|translator}}",
+       "apihelp-cxtranslatorstats-example-1": 
"{{doc-apihelp-example|query+cxtranslatorstats}}"
 }
diff --git a/i18n/en.json b/i18n/en.json
index 222ec27..89d68c6 100644
--- a/i18n/en.json
+++ b/i18n/en.json
@@ -206,5 +206,7 @@
        "cx-suggestionlist-collapse": "View less",
        "cx-suggestionlist-refresh": "Refresh suggestions",
        "cx-notification-suggestions-available": "Based on {{GENDER:$2|your}} 
previous translation of '''$1''', new suggestions are now available.",
-       "cx-notification-suggestions-available-email-subject": "Translation 
suggestions available"
+       "cx-notification-suggestions-available-email-subject": "Translation 
suggestions available",
+       "cx-translator-month-stats-label": "This month",
+       "cx-translator-total-translations-label": "Total"
 }
diff --git a/i18n/qqq.json b/i18n/qqq.json
index 0261b5f..2531e2f 100644
--- a/i18n/qqq.json
+++ b/i18n/qqq.json
@@ -212,5 +212,7 @@
        "cx-suggestionlist-collapse": "Label for the suggestions list collapse 
trigger",
        "cx-suggestionlist-refresh": "Label for the suggestions list refresh 
trigger",
        "cx-notification-suggestions-available": "Echo notification to inform 
the translator about the availability of personalized suggestions. 
\n\nParameters:\n* $1 - Source title of last translated page. \n* $2 - User 
name of current user.",
-       "cx-notification-suggestions-available-email-subject": "Email subject 
to inform the translator about the availability of personalized suggestions"
+       "cx-notification-suggestions-available-email-subject": "Email subject 
to inform the translator about the availability of personalized suggestions",
+       "cx-translator-month-stats-label": "Label displayed in the translation 
statistics of current user.",
+       "cx-translator-total-translations-label": "Label displayed in the 
translation statistics of current user."
 }
diff --git a/includes/Translation.php b/includes/Translation.php
index 66db0cc..c1af385 100644
--- a/includes/Translation.php
+++ b/includes/Translation.php
@@ -292,7 +292,9 @@
         * @param string $interval 'weekly' or 'monthly' trend
         * @return array
         */
-       public static function getTrendByStatus( $source, $target, $status, 
$interval ) {
+       public static function getTrendByStatus(
+               $source, $target, $status, $interval, $translatorId
+       ) {
                $dbr = Database::getConnection( DB_SLAVE );
 
                $conditions = array();
@@ -320,6 +322,9 @@
                if ( $target !== null ) {
                        $conditions['translation_target_language'] = $target;
                }
+               if ( $translatorId !== null ) {
+                       $conditions['translation_last_update_by'] = 
$translatorId;
+               }
                $options = null;
                if ( $interval === 'week' ) {
                        $options = array(
diff --git a/modules/dashboard/ext.cx.dashboard.js 
b/modules/dashboard/ext.cx.dashboard.js
index 2f83c7b..1ac0e2e 100644
--- a/modules/dashboard/ext.cx.dashboard.js
+++ b/modules/dashboard/ext.cx.dashboard.js
@@ -128,12 +128,13 @@
        };
 
        CXDashboard.prototype.buildSidebar = function () {
-               var $header, i, items, $links = [];
+               var $header, $translator, i, items, $links = [];
 
                $header = $( '<div>' )
                        .addClass( 'cx-sidebar__title' )
                        .text( mw.msg( 'cx-dashboard-sidebar-title' ) );
 
+               $translator = mw.cx.widgets.CXTranslator();
                items = this.getSidebarItems();
                $links = $( '<ul>' );
                for ( i = 0; i < items.length; i++ ) {
@@ -152,7 +153,7 @@
 
                return $( '<div>' )
                        .addClass( 'cx-sidebar' )
-                       .append( $header, $links );
+                       .append( $translator, $header, $links );
        };
 
        CXDashboard.prototype.render = function () {
diff --git a/modules/widgets/translator/ext.cx.translator.js 
b/modules/widgets/translator/ext.cx.translator.js
new file mode 100644
index 0000000..1366007
--- /dev/null
+++ b/modules/widgets/translator/ext.cx.translator.js
@@ -0,0 +1,91 @@
+/*!
+ * ContentTranslation extension - Translator Widget.
+ *
+ * @ingroup Extensions
+ * @copyright See AUTHORS.txt
+ * @license GPL-2.0+
+ */
+( function ( $, mw ) {
+       'use strict';
+       var statsRequest;
+
+       mw.cx.widgets = mw.cx.widgets || {};
+
+       function drawChart( ctx, stats ) {
+               var cxTrendChart, data;
+               data = {
+                       labels: Object.keys( 
stats.cxtranslatorstats.publishTrend ),
+                       datasets: [
+                               {
+                                       strokeColor: '#347BFF',
+                                       fillColor: '#347BFF',
+                                       data: $.map( 
stats.cxtranslatorstats.publishTrend, function ( data ) {
+                                               return data.delta;
+                                       } )
+                               }
+                       ]
+               };
+               /*global Chart:false */
+               cxTrendChart = new Chart( ctx ).Bar( data, {
+                       responsive: true,
+                       barDatasetSpacing: 1,
+                       showScale: false,
+                       showTooltips: false
+               } );
+       }
+
+       mw.cx.widgets.CXTranslator = function ( translatorName ) {
+               var $widget, $header, $monthStats, $total, $trend,
+                       api = new mw.Api();
+
+               $header = $( '<div>' ).addClass( 'cx-translator__header' );
+               $monthStats = $( '<div>' ).addClass( 
'cx-translator__month-stats' ).append(
+                       $( '<div>' ).addClass( 
'cx-translator__month-stats-count' ),
+                       $( '<div>' )
+                       .addClass( 'cx-translator__month-stats-label' )
+                       .text( mw.msg( 'cx-translator-month-stats-label' ) )
+               );
+               $total = $( '<div>' ).addClass( 
'cx-translator__total-translations' ).append(
+                       $( '<div>' ).addClass( 
'cx-translator__total-translations-count' ),
+                       $( '<div>' )
+                       .addClass( 'cx-translator__total-translations-label' )
+                       .text( mw.msg( 'cx-translator-total-translations-label' 
) )
+               );
+               $trend = $( '<canvas>' ).attr( {
+                       id: 'cxtranslatorstats',
+                       width: '1000%', // Tricks Chart.js to scale down the 
graph 10 times
+                       height: '100px'
+               } );
+               statsRequest = statsRequest || api.get( {
+                       action: 'query',
+                       list: 'cxtranslatorstats',
+                       translator: translatorName
+               } );
+               $widget = $( '<div>' )
+                       .addClass( 'cx-translator' )
+                       .append( $header, $monthStats, $total, $trend );
+               statsRequest.then( function ( stats ) {
+                       var total, monthCount, ctx,
+                               thisMonthKey = new Date().toISOString().slice( 
0, 7 );
+
+                       if ( !stats.cxtranslatorstats.publishTrend[ 
thisMonthKey ] ) {
+                               $widget.remove();
+                               return;
+                       }
+                       total = stats.cxtranslatorstats.publishTrend[ 
thisMonthKey ].count;
+                       monthCount = stats.cxtranslatorstats.publishTrend[ 
thisMonthKey ].delta;
+
+                       $header.text( stats.cxtranslatorstats.translator );
+                       $total.find( '.cx-translator__total-translations-count' 
).text( total );
+                       $monthStats.find( '.cx-translator__month-stats-count' )
+                               .text( stats.cxtranslatorstats.publishTrend[ 
thisMonthKey ].delta );
+
+                       ctx = $trend[ 0 ].getContext( '2d' );
+                       drawChart( ctx, stats );
+               } ).fail( function () {
+                       $widget.remove();
+               } );
+
+               return $widget;
+       };
+}( jQuery, mediaWiki ) );
diff --git a/modules/widgets/translator/ext.cx.translator.less 
b/modules/widgets/translator/ext.cx.translator.less
new file mode 100644
index 0000000..4271ac3
--- /dev/null
+++ b/modules/widgets/translator/ext.cx.translator.less
@@ -0,0 +1,41 @@
+@import "../../widgets/common/ext.cx.common";
+@import "mediawiki.mixins";
+
+.cx-translator {
+       .mw-ui-item;
+       .mw-ui-one-whole;
+       padding-left: 40px;
+       margin-bottom: 10px;
+       .background-image-svg('images/user-small.svg', 'images/user-small.png');
+       background-size: 25px;
+    background-repeat: no-repeat;
+    background-position: top left;
+}
+
+.cx-translator__header {
+       font-size: larger;
+       color: @gray-dark;
+       font-size: 1.5em;
+}
+
+.cx-translator__month-stats,
+.cx-translator__total-translations {
+       .mw-ui-one-half;
+       color: #565656;
+}
+
+.cx-translator__total-translations-count,
+.cx-translator__month-stats-count {
+       font-size: 2em;
+}
+
+.cx-translator__total-translations-label,
+.cx-translator__month-stats-label {
+       font-size: 1em;
+}
+
+#cxtranslatorstats {
+       .mw-ui-one-whole;
+       max-height: 50px;
+       background-color: #f0f0f0;
+}
diff --git a/modules/widgets/translator/images/user-small.png 
b/modules/widgets/translator/images/user-small.png
new file mode 100644
index 0000000..32e8914
--- /dev/null
+++ b/modules/widgets/translator/images/user-small.png
Binary files differ
diff --git a/modules/widgets/translator/images/user-small.svg 
b/modules/widgets/translator/images/user-small.svg
new file mode 100644
index 0000000..a6d332b
--- /dev/null
+++ b/modules/widgets/translator/images/user-small.svg
@@ -0,0 +1,7 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg"; 
xmlns:xlink="http://www.w3.org/1999/xlink"; x="0px" y="0px" width="15px" 
height="15px" viewBox="0 0 15 15" enable-background="new 0 0 15 15" 
xml:space="preserve">
+<g>
+       <path fill="#777" 
d="M12.281,4.776c0,2.639-2.142,4.783-4.78,4.783c-2.64,0-4.779-2.144-4.779-4.783 
  C2.722,2.138,4.861,0,7.501,0C10.14,0,12.281,2.138,12.281,4.776z"/>
+       <path fill="#777" 
d="M13.36,8.609h-0.947c-1.031,1.625-2.844,2.707-4.912,2.707c-2.068,0-3.883-1.082-4.914-2.707H1.645
   
c-0.445,0-0.799,0.358-0.799,0.801v4.795C0.846,14.641,1.199,15,1.645,15H13.36c0.44,0,0.794-0.359,0.794-0.795V9.41
   C14.154,8.968,13.801,8.609,13.36,8.609z"/>
+</g>
+</svg>

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

Gerrit-MessageType: newchange
Gerrit-Change-Id: I4b4edee1d2031417e51a42077c206d889373d29d
Gerrit-PatchSet: 1
Gerrit-Project: mediawiki/extensions/ContentTranslation
Gerrit-Branch: master
Gerrit-Owner: Santhosh <santhosh.thottin...@gmail.com>

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

Reply via email to