@@ -2,9 +2,6 @@ import React from 'react';
22import { PanelProps } from '@grafana/data' ;
33import { SimpleOptions } from 'types' ;
44import './SimplePanel.css' ;
5- // import { css, cx } from '@emotion/css';
6- // import { useStyles2, useTheme2 } from '@grafana/ui';
7- // import { PanelDataErrorView } from '@grafana/runtime';
85
96interface Props extends PanelProps < SimpleOptions > { }
107
@@ -25,64 +22,89 @@ export const SimplePanel: React.FC<Props> = ({ options, data, width, height }) =
2522
2623 // Handle no data case
2724 if ( ! data . series . length ) {
28- return < div className = "panel-container" > No data to display</ div > ;
25+ return < div className = "panel-container" > No data to display</ div >
2926 }
3027
3128 // Use the first series (Grafana data frame)
3229 const frame = data . series [ 0 ] ;
33-
34- //responsive breakpoint helper
35- const isNarrow = width < 300 ;
3630
37- // Extract rows
38- const rows = Array . from ( { length : frame . length || frame . fields [ 0 ] . values . length } , ( _ , i ) => {
39- const get = ( field ?: string ) => {
40- const f = field ? frame . fields . find ( f => f . name === field ) : undefined ;
41- return f ? f . values . get ( i ) : undefined ;
31+ const length = frame . length || frame . fields [ 0 ] . values . length ;
32+
33+ // helper to get value at specific index
34+ const getValue = ( fieldName : string | undefined , index : number ) => {
35+ if ( ! fieldName ) { return undefined ; }
36+ const field = frame . fields . find ( f => f . name === fieldName ) ;
37+ return field ? field . values [ index ] : undefined ;
4238 } ;
4339
44- return {
45- category : get ( fieldCategory ) ,
46- mentionsPercent : get ( fieldMentionsPercent ) ,
47- mentionsCount : get ( fieldMentionsCount ) ,
48- voicesCount : get ( totalVoicesCount ) ,
49- platformCount : get ( platformVoicesCount ) ,
50- socialCount : get ( socialVoicesCount ) ,
51- languages : get ( fieldLanguage ) ,
52- languagesPercent : get ( fieldLanguagePercent ) ,
53- icon : get ( icon ) ,
54- iconColor : get ( iconColor ) ,
55- statColor : get ( statColor ) ,
40+ // extract KPI stats from the first row
41+ const stats = {
42+ voicesCount : getValue ( totalVoicesCount , 0 ) ,
43+ platformCount : getValue ( platformVoicesCount , 0 ) ,
44+ socialCount : getValue ( socialVoicesCount , 0 ) ,
5645 } ;
57- } ) ;
46+
47+ // extract category rows; filter out empty categories
48+ const platformRows = [ ] ;
49+ for ( let i = 0 ; i < length ; i ++ ) {
50+ const category = getValue ( fieldCategory , i ) ;
51+
52+ // only add to list if category exists
53+ if ( category ) {
54+ platformRows . push ( {
55+ category : category ,
56+ mentionsPercent : getValue ( fieldMentionsPercent , i ) ,
57+ mentionsCount : getValue ( fieldMentionsCount , i ) ,
58+ icon : getValue ( icon , i ) ,
59+ iconColor : getValue ( iconColor , i ) ,
60+ } ) ;
61+ }
62+ }
63+
64+ // extract language rows; filter out empty languages
65+ const languageRows = [ ] ;
66+ for ( let i = 0 ; i < length ; i ++ ) {
67+ const lang = getValue ( fieldLanguage , i ) ;
68+
69+ // only add to list if language exists
70+ if ( lang ) {
71+ languageRows . push ( {
72+ language : lang ,
73+ percent : getValue ( fieldLanguagePercent , i ) ,
74+ } ) ;
75+ }
76+ }
77+
78+ //responsive breakpoint helper
79+ const isNarrow = width < 300 ;
5880
5981 return (
6082 < div className = "panel-container" style = { { width, height } } >
6183
6284 < h2 className = "panel-section-header" > Community Engagement</ h2 >
6385
6486 < div className = { `panel-stats-row ${ isNarrow ? 'is-narrow' : '' } ` }
65- style = { { color : options . statColor } }
87+ style = { { color : statColor } }
6688 >
6789 < div className = "panel-stat-item" >
68- < div className = "panel-stat-value" > { rows [ 0 ] ? .voicesCount ?? 0 } </ div >
90+ < div className = "panel-stat-value" > { stats . voicesCount ?? 0 } </ div >
6991 < div className = "panel-stat-label" > Total Voices</ div >
7092 </ div >
7193
7294 < div className = "panel-stat-item" >
73- < div className = "panel-stat-value" > { rows [ 0 ] ? .platformCount ?? 0 } </ div >
95+ < div className = "panel-stat-value" > { stats . platformCount ?? 0 } </ div >
7496 < div className = "panel-stat-label" > Platform Posts</ div >
7597 </ div >
7698
7799 < div className = "panel-stat-item" >
78- < div className = "panel-stat-value" > { rows [ 0 ] ? .socialCount ?? 0 } </ div >
100+ < div className = "panel-stat-value" > { stats . socialCount ?? 0 } </ div >
79101 < div className = "panel-stat-label" > Social Media</ div >
80102 </ div >
81103 </ div >
82104
83105 < h2 className = "panel-section-header top-spacing" > Platform Breakdown</ h2 >
84106
85- { rows . map ( ( row , i ) => (
107+ { platformRows . map ( ( row , i ) => (
86108 < div key = { i } className = "panel-card" >
87109 { /* row wrapper for icon and details */ }
88110 < div className = { `panel-card-inner ${ isNarrow ? 'is-narrow' : '' } ` } >
@@ -102,7 +124,7 @@ export const SimplePanel: React.FC<Props> = ({ options, data, width, height }) =
102124 < div className = { `panel-card-header-row ${ isNarrow ? 'is-narrow' : '' } ` } >
103125 < h3 className = "panel-category-title" >
104126 { options . showNumbering ? `${ i + 1 } . ` : '' }
105- { row . category ?? 'category' }
127+ { row . category }
106128 </ h3 >
107129
108130 < div className = "panel-percent-pill" >
@@ -123,9 +145,10 @@ export const SimplePanel: React.FC<Props> = ({ options, data, width, height }) =
123145
124146 < h2 className = "panel-section-header top-spacing" > Language Distribution</ h2 >
125147 < div className = "panel-lang-container" >
126- { rows . map ( ( row , i ) => (
148+
149+ { languageRows . map ( ( row , i ) => (
127150 < div key = { i } className = "panel-lang-pill" >
128- { row . languages ?? ' language' } { Number ( row . languagesPercent ?? '0' ) . toFixed (
151+ { row . language } { Number ( row . percent ?? '0' ) . toFixed (
129152 options . decimalPlaces ?? 1 ) } %
130153 </ div >
131154 ) ) }
0 commit comments