• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

michaelmbugua-me / DataAnalyticsPlatform / #5

26 Aug 2025 06:25PM UTC coverage: 20.788% (+0.6%) from 20.144%
#5

push

github

michaelmbugua-me
Add a data exportation service that allows exporting excel and pdf

62 of 502 branches covered (12.35%)

Branch coverage included in aggregate %.

6 of 73 new or added lines in 1 file covered. (8.22%)

479 existing lines in 7 files now uncovered.

265 of 1071 relevant lines covered (24.74%)

1.75 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

10.98
/src/app/features/VisualizationsModule/VisualizationsRawData/VisualizationsRawDataComponent.ts
1
import {Component, effect, inject, OnInit, signal, ChangeDetectionStrategy} from '@angular/core';
1✔
2
import {Button, ButtonDirective, ButtonIcon, ButtonLabel} from 'primeng/button';
1✔
3
import {FormsModule} from '@angular/forms';
1✔
4
import {AgChartOptions} from 'ag-charts-community';
5
import {AgCharts} from 'ag-charts-angular';
1✔
6
import {ProgressSpinner} from 'primeng/progressspinner';
1✔
7
import {DataService} from '../../../core/services/DataService';
1✔
8
import {FilterDrawerComponent} from '../../shared/components/filter-drawer';
1✔
9

10

11
@Component({
12
  selector: 'app-visualizations',
13
  templateUrl: './VisualizationsRawDataComponent.html',
14
  standalone: true,
15
  changeDetection: ChangeDetectionStrategy.OnPush,
16
  imports: [ButtonDirective, ButtonIcon, ButtonLabel, FormsModule, Button, AgCharts, ProgressSpinner, FilterDrawerComponent],
17
  providers: [],
18
  styleUrls: ['./VisualizationsRawDataComponent.scss']
19
})
20
export class VisualizationsRawDataComponent implements OnInit {
1✔
21

22
  private dataService = inject(DataService);
1✔
23

UNCOV
24
  public data = this.dataService.filteredRawData;
×
UNCOV
25
  error = this.dataService.error;
×
26

27

28

29
  performanceChartOptions!: AgChartOptions;
30
  eventsChartOptions!: AgChartOptions;
31
  platformChartOptions!: AgChartOptions;
32
  deviceTierChartOptions!: AgChartOptions;
33
  countryChartOptions!: AgChartOptions;
34
  networkChartOptions!: AgChartOptions;
35

36
  filters!: Filter[];
37

38

39

UNCOV
40
  visible = signal(false);
×
41

42
  // Charts
UNCOV
43
  chartLoaded: any = false;
×
44

45
  constructor() {
46

UNCOV
47
    effect(() => {
×
48

49
      // Derive datasets from current filtered rows
50
      const performanceData = this.getPerformanceData();
×
51
      const eventDistribution = this.getEventDistribution();
×
52
      const platformData = this.getPlatformData();
×
53
      const deviceTierData = this.getDeviceTierData();
×
UNCOV
54
      const countryChartData = this.getCountryData();
×
55
      const networkChartData = this.getNetworkData();
×
56

UNCOV
57
      this.chartLoaded = true;
×
58

59
      // Chart 1: Performance Over Time (App Start Duration)
UNCOV
60
      this.performanceChartOptions = {
×
61
        title: {
62
          text: 'App Start Performance Over Time',
63
        }, data: [...performanceData], series: [{
64
          type: 'line', xKey: 'day', yKey: 'duration_ms', yName: 'App Start Time (ms)',
65
        },], axes: [{
66
          type: 'category', position: 'bottom', title: {
67
            text: 'Date',
68
          },
69
        }, {
70
          type: 'number', position: 'left', title: {
71
            text: 'Duration (ms)',
72
          },
73
        },],
74
      };
75

76
      // Chart 2: Event Distribution
UNCOV
77
      this.eventsChartOptions = {
×
78
        title: {
79
          text: 'User Event Distribution',
80
        }, data: [...eventDistribution], series: [{
81
          type: 'pie', angleKey: 'count', legendItemKey: 'event', calloutLabelKey: 'event'
82
        }],
83
      };
84

85
      // Chart 3: Platform Usage
UNCOV
86
      this.platformChartOptions = {
×
87
        title: {
88
          text: 'Usage by Platform',
89
        },
90
        data: [...platformData],
91
        series: [
92
          {
93
            type: 'bar',
94
            xKey: 'platform',
95
            yKey: 'count',
96
          },
97
        ],
98
        axes: [
99
          {
100
            type: 'category',
101
            position: 'bottom',
102
          },
103
          {
104
            type: 'number',
105
            position: 'left',
106
            title: {
107
              text: 'Number of Events',
108
            },
109
          },
110
        ],
111
      };
112

113
      // Chart 4: Performance by Device Tier
UNCOV
114
      this.deviceTierChartOptions = {
×
115
        title: {
116
          text: 'Performance by Device Tier',
117
        },
118
        data: [...deviceTierData],
119
        series: [
120
          {
121
            type: 'bar',
122
            xKey: 'device_tier',
123
            yKey: 'avg_duration',
124
            yName: 'Average Duration (ms)',
125
          },
126
        ],
127
        axes: [
128
          {
129
            type: 'category',
130
            position: 'bottom',
131
            title: {
132
              text: 'Device Tier',
133
            },
134
          },
135
          {
136
            type: 'number',
137
            position: 'left',
138
            title: {
139
              text: 'Average Duration (ms)',
140
            },
141
          },
142
        ],
143
      };
144

145
      // Chart 5: Usage by Country
UNCOV
146
      this.countryChartOptions = {
×
147
        title: {
148
          text: 'Usage by Country',
149
        },
150
        data: [...countryChartData],
151
        series: [
152
          {
153
            type: 'pie',
154
            angleKey: 'count',
155
            legendItemKey: 'country',
156
            calloutLabelKey: 'country',
157
          },
158
        ],
159
      };
160

161
      // Chart 6: Performance by Network Type
UNCOV
162
      this.networkChartOptions = {
×
163
        title: {
164
          text: 'Performance by Network Type',
165
        },
166
        data: [...networkChartData],
167
        series: [
168
          {
169
            type: 'bar',
170
            xKey: 'network_type',
171
            yKey: 'avg_duration',
172
            yName: 'Average Duration (ms)',
173
          },
174
        ],
175
        axes: [
176
          {
177
            type: 'category',
178
            position: 'bottom',
179
            title: {
180
              text: 'Network Type',
181
            },
182
          },
183
          {
184
            type: 'number',
185
            position: 'left',
186
            title: {
187
              text: 'Average Duration (ms)',
188
            },
189
          },
190
        ],
191
      };
192

193
    });
194

195
  }
196

197
  getEventDistribution() {
198
    const eventCounts: any = {};
×
199
    this.data().forEach((item: any) => {
×
UNCOV
200
      if (item.event_name) {
×
UNCOV
201
        eventCounts[item.event_name] = (eventCounts[item.event_name] || 0) + 1;
×
202
      }
203
    });
204

UNCOV
205
    return Object.keys(eventCounts).map(event => ({
×
206
      event, count: eventCounts[event]
207
    }));
208
  }
209

210
  getPerformanceData() {
211
    return this.data()
×
UNCOV
212
      .filter(item => item.source === 'performance' && item.perf_type === 'app_start')
×
UNCOV
213
      .map(item => ({
×
214
        day: item.day, duration_ms: item.duration_ms, platform: item.platform
215
      }));
216
  }
217

218
  getPlatformData() {
219
    const platformCounts: any = {};
×
UNCOV
220
    this.data().forEach((item: any) => {
×
UNCOV
221
      platformCounts[item.platform] = (platformCounts[item.platform] || 0) + 1;
×
222
    });
223

UNCOV
224
    return Object.keys(platformCounts).map((platform) => ({
×
225
      platform,
226
      count: platformCounts[platform]
227
    }));
228
  }
229

230
  getDeviceTierData() {
UNCOV
231
    const tierData: any = {};
×
232
    const tierCounts: any = {};
×
233

UNCOV
234
    this.data()
×
235
      .filter((item: any) => item.duration_ms)
×
236
      .forEach((item: any) => {
237
        if (!tierData[item.device_tier]) {
×
UNCOV
238
          tierData[item.device_tier] = 0;
×
239
          tierCounts[item.device_tier] = 0;
×
240
        }
UNCOV
241
        tierData[item.device_tier] += item.duration_ms;
×
UNCOV
242
        tierCounts[item.device_tier]++;
×
243
      });
244

UNCOV
245
    return Object.keys(tierData).map(tier => ({
×
246
      device_tier: tier,
247
      avg_duration: Math.round(tierData[tier] / tierCounts[tier])
248
    }));
249
  }
250

251
  getCountryData() {
252
    const countryCounts: any = {};
×
UNCOV
253
    this.data().forEach(item => {
×
UNCOV
254
      countryCounts[item.country] = (countryCounts[item.country] || 0) + 1;
×
255
    });
256

UNCOV
257
    return Object.keys(countryCounts).map(country => ({
×
258
      country,
259
      count: countryCounts[country]
260
    }));
261
  }
262

263
  getNetworkData() {
UNCOV
264
    const networkData: any = {};
×
265
    const networkCounts: any = {};
×
266

UNCOV
267
    this.data()
×
268
      .filter((item: any) => item.duration_ms && item.network_type)
×
269
      .forEach((item: any) => {
270
        if (!networkData[item.network_type]) {
×
UNCOV
271
          networkData[item.network_type] = 0;
×
272
          networkCounts[item.network_type] = 0;
×
273
        }
UNCOV
274
        networkData[item.network_type] += item.duration_ms;
×
UNCOV
275
        networkCounts[item.network_type]++;
×
276
      });
277

UNCOV
278
    return Object.keys(networkData).map(network => ({
×
279
      network_type: network,
280
      avg_duration: Math.round(networkData[network] / networkCounts[network])
281
    }));
282
  }
283

284

285
  async ngOnInit() {
286

UNCOV
287
    this.filters = [{name: 'Today\'s records', code: 'NY'}, {
×
288
      name: 'This weeks\'s records', code: 'RM'
289
    }, {name: 'This month\'s records', code: 'LDN'}, {name: 'This year\'s records', code: 'IST'}];
290
  }
291

292
  toggleFilterVisibility() {
UNCOV
293
    this.visible.update(v => !v);
×
294
  }
295

296

297

UNCOV
298
  protected readonly Date = Date;
×
299
}
300

301
interface Filter {
302
  name: string,
303
  code: string
304
}
305

STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc