Santhosh has uploaded a new change for review. https://gerrit.wikimedia.org/r/236529
Change subject: Stats: Separate total and language graph, and show draft count in graph ...................................................................... Stats: Separate total and language graph, and show draft count in graph This is in preparation for showing deletion stats and weekly trend graphs. Showing both total and language specific stats is difficult to understand because the difference is widening fast. So separated them. ApiQueryContentTranslationLanguageTrend now return cumulative count for translations in progress as well. Soon it should retun cumulative deleted stats too. Bug: T105192 Bug: T90538 Change-Id: Ifd4bd0e3a92ac022428edf3915552ea99142dbfb --- M api/ApiQueryContentTranslationLanguageTrend.php M includes/Translation.php M modules/stats/ext.cx.stats.js M modules/stats/styles/ext.cx.stats.less 4 files changed, 196 insertions(+), 47 deletions(-) git pull ssh://gerrit.wikimedia.org:29418/mediawiki/extensions/ContentTranslation refs/changes/29/236529/1 diff --git a/api/ApiQueryContentTranslationLanguageTrend.php b/api/ApiQueryContentTranslationLanguageTrend.php index cd5bf33..e8b9e43 100644 --- a/api/ApiQueryContentTranslationLanguageTrend.php +++ b/api/ApiQueryContentTranslationLanguageTrend.php @@ -32,7 +32,10 @@ $result->addValue( array( 'query' ), 'contenttranslationlangtrend', - ContentTranslation\Translation::getTrend( $source, $target, $interval ) + array( + 'translations' => ContentTranslation\Translation::getPublishTrend( $source, $target, $interval ), + 'drafts' => ContentTranslation\Translation::getDraftTrend( $source, $target, $interval ) + ) ); } diff --git a/includes/Translation.php b/includes/Translation.php index c0a7c98..59c4a2d 100644 --- a/includes/Translation.php +++ b/includes/Translation.php @@ -211,10 +211,90 @@ } /** + * Get time-wise cumulative number of drafts for given + * language pairs, with given interval. + */ + public static function getDraftTrend( $source, $target, $interval ) { + $dbr = Database::getConnection( DB_SLAVE ); + + $draftCondition = $dbr->makeList( + array( + 'translation_status' => 'draft', + 'translation_target_url IS NULL' + ), + LIST_AND + ); + + $groupBy = null; + + if ( $interval === 'week' ) { + $groupBy = array( + 'GROUP BY' => array( + 'YEARWEEK(translation_last_updated_timestamp)', + ), + ); + } elseif ( $interval === 'month' ) { + $groupBy = array( + 'GROUP BY' => array( + 'YEAR(translation_last_updated_timestamp), MONTH(translation_last_updated_timestamp)', + ), + ); + } + + $conditions = array( $draftCondition ); + + if ( $source !== null ) { + $conditions['translation_source_language'] = $source; + } + + if ( $target !== null ) { + $conditions['translation_target_language'] = $target; + } + + $rows = $dbr->select( + array( 'translations' => 'cx_translations' ), + array( + "DATE_FORMAT( translations.translation_last_updated_timestamp, '%Y-%m-%d' ) AS date", + '(' . $dbr->selectSQLText( + 'cx_translations', + 'count(*)', + $dbr->makeList( array( + 'translation_last_updated_timestamp <= MAX(translations.translation_last_updated_timestamp)', + $dbr->makeList( $conditions, LIST_AND ), + ), + LIST_AND ) + ) . ') translatons_count', + ), + $dbr->makeList( $conditions, LIST_AND ), + __METHOD__, + $groupBy + ); + + $prev = 0; + $result = array(); + foreach ( $rows as $row ) { + $count = (int)$row->translatons_count; + $result[] = array( + 'date' => $interval === 'week' ? + // Week end date + date( 'Y-m-d', strtotime( $row->date . ' + ' . + ( 6 - date( 'w', strtotime( $row->date ) ) ) . ' days' ) ) : + date( 'Y-m', strtotime( $row->date ) ), + 'count' => $count, + 'delta' => $count - $prev, + ); + + $prev = $count; + } + + return $result; + } + + /** * Get time-wise cumulative number of translations for given * language pairs, with given interval. */ - public static function getTrend( $source, $target, $interval ) { + public static function getPublishTrend( $source, $target, $interval ) { $dbr = Database::getConnection( DB_SLAVE ); $publishedCondition = $dbr->makeList( diff --git a/modules/stats/ext.cx.stats.js b/modules/stats/ext.cx.stats.js index 15bd6fc..769cba3 100644 --- a/modules/stats/ext.cx.stats.js +++ b/modules/stats/ext.cx.stats.js @@ -32,8 +32,14 @@ $( '<div>' ).addClass( 'bounce3' ) ); this.$highlights = $( '<div>' ).addClass( 'cx-stats-highlights' ); - this.$graph = $( '<canvas>' ).attr( { - id: 'cxtrend', + this.$cumlativeGraph = $( '<canvas>' ).attr( { + id: 'cxcumulative', + width: this.$container.width() - 200, // Leave a 200px margin buffer to avoid overflow + height: 400 + } ); + + this.$languageCumulativeGraph = $( '<canvas>' ).attr( { + id: 'cxlangcumulative', width: this.$container.width() - 200, // Leave a 200px margin buffer to avoid overflow height: 400 } ); @@ -42,18 +48,28 @@ $spinner, this.$highlights, $( '<h2>' ).text( mw.msg( 'cx-stats-published-translations-title' ) ), - $( '<div>' ).addClass( 'cx-stats-trend' ).append( this.$graph ) + $( '<div>' ).addClass( 'cx-stats-cumulative__total' ).append( this.$cumlativeGraph ), + $( '<h2>' ).text( mw.message( + 'cx-trend-translations-to', + $.uls.data.getAutonym( mw.config.get( 'wgContentLanguage' ) ) + ).escaped() ), + $( '<div>' ).addClass( 'cx-stats-cumulative__lang' ).append( this.$languageCumulativeGraph ) ); $.when( this.getCXTrends(), this.getCXTrends( mw.config.get( 'wgContentLanguage' ) ) ).done( function ( totalTrend, languageTrend ) { - self.totalTranslationTrend = totalTrend; - self.languageTranslationTrend = languageTrend; - self.languageTranslationTrend = mergeAndFill( totalTrend, languageTrend ); + self.totalTranslationTrend = totalTrend.translations; + self.languageTranslationTrend = languageTrend.translations; + self.languageTranslationTrend = mergeAndFill( self.totalTranslationTrend, self.languageTranslationTrend ); + + self.totalDraftTrend = mergeAndFill( self.totalTranslationTrend, totalTrend.drafts ); + self.languageDraftTrend = mergeAndFill( self.languageTranslationTrend, languageTrend.drafts ); + self.languageDraftTrend = mergeAndFill( self.totalDraftTrend, self.languageDraftTrend ); self.renderHighlights(); - self.drawGraph( 'count' ); + self.drawCumulativeGraph( 'count' ); + self.drawLanguageCumulativeGraph( 'count' ); } ); this.getCXStats().then( function ( data ) { if ( !data || !data.query ) { @@ -127,8 +143,7 @@ 'cx-stats-local-published-number', fmt( langTotal ), fmt( localLanguage ) - ) - ) + ) ) ); weekLangTrendText = mw.msg( 'percent', fmt( weekLangTrend ) ); @@ -368,7 +383,9 @@ $total = $( '<a>' ) .addClass( 'cx-stats-chart__total' ) .prop( 'href', mw.cx.siteMapper.getPageUrl( - model[ i ].language, 'Special:NewPages', { tagfilter: 'contenttranslation' } + model[ i ].language, 'Special:NewPages', { + tagfilter: 'contenttranslation' + } ) ) .text( fmt( model[ i ][ property ] ) ); } else { @@ -424,10 +441,10 @@ } ); }; - CXStats.prototype.drawGraph = function ( type ) { - var data, cxTrendGraph, ctx; + CXStats.prototype.drawCumulativeGraph = function ( type ) { + var data, cxCumulativeGraph, ctx; - ctx = this.$graph[ 0 ].getContext( '2d' ); + ctx = this.$cumlativeGraph[ 0 ].getContext( '2d' ); data = { labels: $.map( this.totalTranslationTrend, function ( data ) { @@ -435,34 +452,88 @@ } ), datasets: [ { - label: mw.message( 'cx-trend-all-translations' ).escaped(), - strokeColor: '#FD6E8A', - pointColor: '#FD6E8A', + label: mw.msg( 'cx-trend-all-translations' ), + fillColor: 'rgba(70, 130, 180, 0.2)', + strokeColor: 'rgba(70, 130, 180, 1)', + pointColor: 'rgba(70, 130, 180, 1)', + pointStrokeColor: '#fff', + pointHighlightFill: '#fff', + pointHighlightStroke: 'rgba(70, 130, 180, 1)', data: $.map( this.totalTranslationTrend, function ( data ) { - return data[type]; + return data[ type ]; } ) }, { - label: mw.message( - 'cx-trend-translations-to', - $.uls.data.getAutonym( mw.config.get( 'wgContentLanguage' ) ) - ).escaped(), - strokeColor: '#80B3FF', - pointColor: '#80B3FF', - data: $.map( this.languageTranslationTrend, function ( data ) { - return data[type]; + label: mw.msg( 'cx-stats-draft-translations-title' ), + fillColor: 'rgba(220,220,220,0.2)', + strokeColor: 'rgba(220,220,220,1)', + pointColor: 'rgba(220,220,220,1)', + pointStrokeColor: '#fff', + pointHighlightFill: '#fff', + pointHighlightStroke: 'rgba(220,220,220,1)', + data: $.map( this.totalDraftTrend, function ( data ) { + return data[ type ]; } ) } ] }; /*global Chart:false */ - cxTrendGraph = new Chart( ctx ).Line( data, { + cxCumulativeGraph = new Chart( ctx ).Line( data, { + responsive: true, datasetFill: false, legendTemplate: '<ul><% for (var i=0; i<datasets.length; i++){%><li style=\"color:<%=datasets[i].strokeColor%>\"><%if(datasets[i].label){%><%=datasets[i].label%><%}%></li><%}%></ul>' } ); - this.$container.find( '.cx-stats-trend' ).append( cxTrendGraph.generateLegend() ); + this.$container.find( '.cx-stats-cumulative__total' ).append( cxCumulativeGraph.generateLegend() ); + }; + + CXStats.prototype.drawLanguageCumulativeGraph = function ( type ) { + var data, cxCumulativeGraph, ctx; + + ctx = this.$languageCumulativeGraph[ 0 ].getContext( '2d' ); + + data = { + labels: $.map( this.totalTranslationTrend, function ( data ) { + return data.date; + } ), + datasets: [ + { + label: mw.message( + 'cx-trend-translations-to', + $.uls.data.getAutonym( mw.config.get( 'wgContentLanguage' ) ) + ).escaped(), + strokeColor: 'rgba(70, 130, 180, 1)', + pointColor: 'rgba(70, 130, 180, 1)', + pointStrokeColor: '#fff', + pointHighlightFill: '#fff', + pointHighlightStroke: 'rgba(70, 130, 180, 1)', + data: $.map( this.languageTranslationTrend, function ( data ) { + return data[ type ]; + } ) + }, + { + label: mw.msg( 'cx-stats-draft-translations-title' ), + strokeColor: 'rgba(220, 220, 220, 1)', + pointColor: 'rgba(220, 220, 220, 1 )', + pointStrokeColor: '#fff', + pointHighlightFill: '#fff', + pointHighlightStroke: 'rgba(220,220,220,1)', + data: $.map( this.languageDraftTrend, function ( data ) { + return data[ type ]; + } ) + } + ] + }; + + /*global Chart:false */ + cxCumulativeGraph = new Chart( ctx ).Line( data, { + datasetFill: false, + responsive: true, + legendTemplate: '<ul><% for (var i=0; i<datasets.length; i++){%><li style=\"color:<%=datasets[i].strokeColor%>\"><%if(datasets[i].label){%><%=datasets[i].label%><%}%></li><%}%></ul>' + } ); + + this.$container.find( '.cx-stats-cumulative__lang' ).append( cxCumulativeGraph.generateLegend() ); }; CXStats.prototype.transformJsonToModel = function ( records ) { @@ -557,8 +628,7 @@ * @return {[Object]} Array of translations to a particular language, after padding */ function mergeAndFill( totalData, languageData ) { - var i, - padding = []; + var i; if ( totalData.length === languageData.length ) { return languageData; @@ -570,23 +640,18 @@ if ( !languageData || languageData.length === 0 ) { break; } - - if ( totalData[ i ].date === languageData[ 0 ].date ) { - languageData = padding.concat( languageData ); - } else { - padding.push( { - date: totalData[ i ].date, - count: 0 + if ( languageData[ i ] && new Date( totalData[ i ].date ) > new Date( languageData[ i ].date ) ) { + totalData.splice( i, 0, { + date: languageData[ i ].date, + count: totalData[ i - 1 ] ? totalData[ i - 1 ].count : 0 } ); } - } - - // Fill at the end if languageData is shorter than totalData - for ( i = languageData.length; i < totalData.length; i++ ) { - languageData.push( { - date: totalData[ i ].date, - count: languageData.length ? languageData[ i - 1 ].count : 0 - } ); + if ( !languageData[ i ] || new Date( totalData[ i ].date ) < new Date( languageData[ i ].date ) ) { + languageData.splice( i, 0, { + date: totalData[ i ].date, + count: languageData[ i - 1 ] ? languageData[ i - 1 ].count : 0 + } ); + } } return languageData; diff --git a/modules/stats/styles/ext.cx.stats.less b/modules/stats/styles/ext.cx.stats.less index c5ef8b9..126b0fc 100644 --- a/modules/stats/styles/ext.cx.stats.less +++ b/modules/stats/styles/ext.cx.stats.less @@ -150,7 +150,8 @@ text-align: left; } -.cx-stats-trend { +.cx-stats-cumulative__lang, +.cx-stats-cumulative__total { background-color: #fff; } -- To view, visit https://gerrit.wikimedia.org/r/236529 To unsubscribe, visit https://gerrit.wikimedia.org/r/settings Gerrit-MessageType: newchange Gerrit-Change-Id: Ifd4bd0e3a92ac022428edf3915552ea99142dbfb 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