@@ -23,6 +23,12 @@ var myMoment = moment;
2323 */
2424OCA . Analytics . Visualization = {
2525 defaultColorPalette : [ "#1A366C" , "#EA6A47" , "#a3acb9" , "#6AB187" , "#39a7db" , "#c85200" , "#57606c" , "#a3cce9" , "#ffbc79" , "#c8d0d9" ] ,
26+ timeAggregationFormats : {
27+ day : 'YYYY-MM-DD' ,
28+ week : 'YYYY-MM-DD' ,
29+ month : 'YYYY-MM' ,
30+ year : 'YYYY' ,
31+ } ,
2632
2733 _hexToRgbCache : { } ,
2834
@@ -184,7 +190,17 @@ OCA.Analytics.Visualization = {
184190 } ,
185191 } ;
186192
187- ( { data, columns} = this . convertDataToDataTableFormat ( jsondata . data , tableOptions , jsondata . header ) ) ;
193+ const timeAggregationDisplayConfig = this . getTimeAggregationTableDisplayConfig (
194+ jsondata . options ?. filteroptions ,
195+ jsondata . options ?. chartoptions
196+ ) ;
197+
198+ ( { data, columns} = this . convertDataToDataTableFormat (
199+ jsondata . data ,
200+ tableOptions ,
201+ jsondata . header ,
202+ timeAggregationDisplayConfig
203+ ) ) ;
188204 const calculatedResult = this . dataTableCalculatedColumns ( data , columns , tableOptions ) ;
189205 if ( Array . isArray ( calculatedResult ) ) {
190206 data = calculatedResult ;
@@ -261,9 +277,10 @@ OCA.Analytics.Visualization = {
261277 * @param {Array } originalData - Raw matrix style data rows
262278 * @param {Object } tableOptions - DataTable related options
263279 * @param {Array } header - Original header row
280+ * @param {Object|null } timeAggregationDisplayConfig - Optional table-only formatting config for aggregated time labels
264281 * @returns {{data: Array, columns: Array} }
265282 */
266- convertDataToDataTableFormat : function ( originalData , tableOptions , header ) {
283+ convertDataToDataTableFormat : function ( originalData , tableOptions , header , timeAggregationDisplayConfig = null ) {
267284 let layoutConfig = tableOptions . layout !== undefined ? tableOptions . layout : false ;
268285 let uniqueHeaders = new Set ( ) ;
269286 let transformedData = { } ;
@@ -275,8 +292,14 @@ OCA.Analytics.Visualization = {
275292
276293 // create the columns. default alignment is left
277294 columns = header . map ( ( header , index ) => ( { title : _ . escape ( header ) , className : '' } ) ) ;
295+ if ( timeAggregationDisplayConfig ) {
296+ this . applyTimeAggregationDisplayRenderer ( columns , timeAggregationDisplayConfig . dimension , timeAggregationDisplayConfig ) ;
297+ }
278298 data = originalData . map ( row =>
279299 row . map ( ( value , index ) => {
300+ if ( timeAggregationDisplayConfig && index === timeAggregationDisplayConfig . dimension ) {
301+ return value ;
302+ }
280303 if ( ! isNaN ( parseFloat ( value ) ) && index !== 0 && tableOptions . formatLocales === undefined ) {
281304 // Any number gets aligned to the right and formated with locales
282305 if ( parseInt ( value ) > 1950 && parseInt ( value ) < 2050 && index < 2 ) {
@@ -299,34 +322,55 @@ OCA.Analytics.Visualization = {
299322 // Use titles from the headers array based on the reordered sequence (indices)
300323 columns = layoutConfig . rows . map ( ( index , i ) => ( {
301324 title : _ . escape ( header [ index ] ) ,
302- className : i > 0 ? 'dt-right' : ''
325+ className : i > 0 && ( ! timeAggregationDisplayConfig || index !== timeAggregationDisplayConfig . dimension ) ? 'dt-right' : ''
303326 } ) ) ;
327+ if ( timeAggregationDisplayConfig ) {
328+ const displayIndex = layoutConfig . rows . indexOf ( timeAggregationDisplayConfig . dimension ) ;
329+ if ( displayIndex !== - 1 ) {
330+ this . applyTimeAggregationDisplayRenderer ( columns , displayIndex , timeAggregationDisplayConfig ) ;
331+ }
332+ }
304333
305334 const rowsLength = layoutConfig . rows . length ; // Cache length to avoid repeated property access
306335
307336 // Reorder the data according to the new column sequence
308337 data = originalData . map ( row =>
309338 layoutConfig . rows . map ( ( index , i ) =>
310- i === rowsLength - 1 ? _ . escape ( parseFloat ( row [ index ] ) . toLocaleString ( ) ) : _ . escape ( row [ index ] )
339+ ( timeAggregationDisplayConfig && index === timeAggregationDisplayConfig . dimension )
340+ ? row [ index ]
341+ : ( i === rowsLength - 1 ? _ . escape ( parseFloat ( row [ index ] ) . toLocaleString ( ) ) : _ . escape ( row [ index ] ) )
311342 )
312343 ) ;
313344 } else {
314345 // Case for pivot like rearrangement of the table
315346
316347 // 1. Extract unique headers and initialize transformedData
317348 originalData . forEach ( row => {
318- const columnHeader = row [ layoutConfig . columns [ 0 ] ] ;
349+ let columnHeader = row [ layoutConfig . columns [ 0 ] ] ;
350+ if ( timeAggregationDisplayConfig && layoutConfig . columns [ 0 ] === timeAggregationDisplayConfig . dimension ) {
351+ columnHeader = this . formatTimeAggregationDisplayValue ( columnHeader , timeAggregationDisplayConfig ) ;
352+ }
319353 uniqueHeaders . add ( columnHeader ) ;
320- transformedData [ row [ layoutConfig . rows [ 0 ] ] ] = { } ;
354+ let rowHeader = row [ layoutConfig . rows [ 0 ] ] ;
355+ if ( timeAggregationDisplayConfig && layoutConfig . rows [ 0 ] === timeAggregationDisplayConfig . dimension ) {
356+ rowHeader = this . formatTimeAggregationDisplayValue ( rowHeader , timeAggregationDisplayConfig ) ;
357+ }
358+ transformedData [ rowHeader ] = { } ;
321359 } ) ;
322360
323361 // Sort the headers for consistent ordering
324362 uniqueHeaders = Array . from ( uniqueHeaders ) . sort ( ) ;
325363
326364 // 2. Transform the data
327365 originalData . forEach ( row => {
328- const rowHeader = row [ layoutConfig . rows [ 0 ] ] ;
329- const columnHeader = row [ layoutConfig . columns [ 0 ] ] ;
366+ let rowHeader = row [ layoutConfig . rows [ 0 ] ] ;
367+ let columnHeader = row [ layoutConfig . columns [ 0 ] ] ;
368+ if ( timeAggregationDisplayConfig && layoutConfig . rows [ 0 ] === timeAggregationDisplayConfig . dimension ) {
369+ rowHeader = this . formatTimeAggregationDisplayValue ( rowHeader , timeAggregationDisplayConfig ) ;
370+ }
371+ if ( timeAggregationDisplayConfig && layoutConfig . columns [ 0 ] === timeAggregationDisplayConfig . dimension ) {
372+ columnHeader = this . formatTimeAggregationDisplayValue ( columnHeader , timeAggregationDisplayConfig ) ;
373+ }
330374 const dataValue = row [ layoutConfig . measures [ 0 ] ] ;
331375 transformedData [ rowHeader ] [ columnHeader ] = dataValue ;
332376 } ) ;
@@ -1229,6 +1273,70 @@ OCA.Analytics.Visualization = {
12291273 return idx ;
12301274 } ,
12311275
1276+ getTimeAggregationFormat : function ( grouping ) {
1277+ return this . timeAggregationFormats [ grouping ] || null ;
1278+ } ,
1279+
1280+ getTimeAggregationTableDisplayConfig : function ( filteroptions , chartoptions ) {
1281+ const grouping = filteroptions ?. timeAggregation ?. grouping ;
1282+ if ( ! grouping || grouping === 'none' ) {
1283+ return null ;
1284+ }
1285+
1286+ const format = this . getTimeAggregationFormat ( grouping ) ;
1287+ if ( ! format ) {
1288+ return null ;
1289+ }
1290+
1291+ const dimension = this . resolveDimensionIndex (
1292+ filteroptions . timeAggregation . dimension ,
1293+ filteroptions ?. drilldown
1294+ ) ;
1295+ if ( dimension < 0 ) {
1296+ return null ;
1297+ }
1298+
1299+ const parser = chartoptions ?. scales ?. x ?. time ?. parser || null ;
1300+ return { dimension, format, parser} ;
1301+ } ,
1302+
1303+ formatTimeAggregationDisplayValue : function ( value , config ) {
1304+ if ( value === null || value === undefined || value === '' ) {
1305+ return '' ;
1306+ }
1307+
1308+ let date ;
1309+ if ( ! isNaN ( value ) && value !== '' ) {
1310+ const rawValue = String ( value ) ;
1311+ const numericValue = parseInt ( rawValue , 10 ) ;
1312+ date = rawValue . length > 10 ? new Date ( numericValue ) : new Date ( numericValue * 1000 ) ;
1313+ } else if ( config ?. parser ) {
1314+ date = myMoment ( value , config . parser ) . toDate ( ) ;
1315+ } else {
1316+ date = new Date ( value ) ;
1317+ }
1318+
1319+ if ( isNaN ( date ?. valueOf ?. ( ) ) ) {
1320+ return value ;
1321+ }
1322+
1323+ return myMoment ( date ) . format ( config . format ) ;
1324+ } ,
1325+
1326+ applyTimeAggregationDisplayRenderer : function ( columns , columnIndex , config ) {
1327+ if ( ! columns [ columnIndex ] ) {
1328+ return ;
1329+ }
1330+
1331+ columns [ columnIndex ] . render = function ( data , type ) {
1332+ if ( type !== 'display' && type !== 'filter' ) {
1333+ return data ;
1334+ }
1335+
1336+ return _ . escape ( OCA . Analytics . Visualization . formatTimeAggregationDisplayValue ( data , config ) ) ;
1337+ } ;
1338+ } ,
1339+
12321340 /**
12331341 * Group time based dimensions by day/week/month/year.
12341342 *
0 commit comments