@@ -3510,61 +3510,90 @@ func (q *FakeQuerier) GetTemplateInsightsByTemplate(_ context.Context, arg datab
3510
3510
q .mutex .RLock ()
3511
3511
defer q .mutex .RUnlock ()
3512
3512
3513
- /*
3514
- SELECT
3515
- template_id,
3516
- COUNT(DISTINCT user_id) AS active_users,
3517
- (SUM(usage_mins) * 60)::bigint AS usage_total_seconds, -- Includes app usage.
3518
- (SUM(ssh_mins) * 60)::bigint AS usage_ssh_seconds,
3519
- (SUM(sftp_mins) * 60)::bigint AS usage_sftp_seconds,
3520
- (SUM(reconnecting_pty_mins) * 60)::bigint AS usage_reconnecting_pty_seconds,
3521
- (SUM(vscode_mins) * 60)::bigint AS usage_vscode_seconds,
3522
- (SUM(jetbrains_mins) * 60)::bigint AS usage_jetbrains_seconds
3523
- FROM
3524
- template_usage_stats
3525
- WHERE
3526
- start_time >= @start_time::timestamptz
3527
- AND end_time <= @end_time::timestamptz
3528
- GROUP BY template_id;
3529
- */
3513
+ // map time.Time x TemplateID x UserID x <usage>
3514
+ appUsageByTemplateAndUser := map [time.Time ]map [uuid.UUID ]map [uuid.UUID ]database.GetTemplateInsightsByTemplateRow {}
3530
3515
3531
- type grouped struct {
3532
- database.GetTemplateInsightsByTemplateRow
3533
- activeUserIDs map [uuid.UUID ]struct {}
3534
- }
3535
- groupedByTemplateID := make (map [uuid.UUID ]grouped )
3536
- for _ , tus := range q .templateUsageStats {
3537
- if tus .StartTime .Before (arg .StartTime ) || tus .EndTime .After (arg .EndTime ) {
3516
+ // Review agent stats in terms of usage
3517
+ templateIDSet := make (map [uuid.UUID ]struct {})
3518
+
3519
+ for _ , s := range q .workspaceAgentStats {
3520
+ if s .CreatedAt .Before (arg .StartTime ) || s .CreatedAt .Equal (arg .EndTime ) || s .CreatedAt .After (arg .EndTime ) {
3538
3521
continue
3539
3522
}
3540
- row , ok := groupedByTemplateID [tus .TemplateID ]
3541
- if ! ok {
3542
- row = grouped {
3543
- GetTemplateInsightsByTemplateRow : database.GetTemplateInsightsByTemplateRow {
3544
- TemplateID : tus .TemplateID ,
3545
- },
3546
- activeUserIDs : make (map [uuid.UUID ]struct {}),
3547
- }
3523
+ if s .ConnectionCount == 0 {
3524
+ continue
3525
+ }
3526
+
3527
+ t := s .CreatedAt .Truncate (time .Minute )
3528
+ templateIDSet [s .TemplateID ] = struct {}{}
3529
+
3530
+ if _ , ok := appUsageByTemplateAndUser [t ]; ! ok {
3531
+ appUsageByTemplateAndUser [t ] = make (map [uuid.UUID ]map [uuid.UUID ]database.GetTemplateInsightsByTemplateRow )
3532
+ }
3533
+
3534
+ if _ , ok := appUsageByTemplateAndUser [t ][s.TemplateID ]; ! ok {
3535
+ appUsageByTemplateAndUser [t ][s.TemplateID ] = make (map [uuid.UUID ]database.GetTemplateInsightsByTemplateRow )
3536
+ }
3537
+
3538
+ if _ , ok := appUsageByTemplateAndUser [t ][s.TemplateID ][s .UserID ]; ! ok {
3539
+ appUsageByTemplateAndUser [t ][s.TemplateID ][s .UserID ] = database.GetTemplateInsightsByTemplateRow {}
3540
+ }
3541
+
3542
+ u := appUsageByTemplateAndUser [t ][s.TemplateID ][s .UserID ]
3543
+ if s .SessionCountJetBrains > 0 {
3544
+ u .UsageJetbrainsSeconds = 60
3545
+ }
3546
+ if s .SessionCountVSCode > 0 {
3547
+ u .UsageVscodeSeconds = 60
3548
+ }
3549
+ if s .SessionCountReconnectingPTY > 0 {
3550
+ u .UsageReconnectingPtySeconds = 60
3551
+ }
3552
+ if s .SessionCountSSH > 0 {
3553
+ u .UsageSshSeconds = 60
3548
3554
}
3549
- row .activeUserIDs [tus .UserID ] = struct {}{}
3550
- row .ActiveUsers = int64 (len (row .activeUserIDs ))
3551
- row .UsageTotalSeconds += int64 (tus .UsageMins ) * 60
3552
- row .UsageSshSeconds += int64 (tus .SshMins ) * 60
3553
- row .UsageSftpSeconds += int64 (tus .SftpMins ) * 60
3554
- row .UsageReconnectingPtySeconds += int64 (tus .ReconnectingPtyMins ) * 60
3555
- row .UsageVscodeSeconds += int64 (tus .VscodeMins ) * 60
3556
- row .UsageJetbrainsSeconds += int64 (tus .JetbrainsMins ) * 60
3557
- groupedByTemplateID [tus .TemplateID ] = row
3555
+ appUsageByTemplateAndUser [t ][s.TemplateID ][s .UserID ] = u
3558
3556
}
3559
3557
3560
- var rows []database.GetTemplateInsightsByTemplateRow
3561
- for _ , row := range groupedByTemplateID {
3562
- rows = append (rows , row .GetTemplateInsightsByTemplateRow )
3558
+ // Sort used templates
3559
+ templateIDs := make ([]uuid.UUID , 0 , len (templateIDSet ))
3560
+ for templateID := range templateIDSet {
3561
+ templateIDs = append (templateIDs , templateID )
3563
3562
}
3564
- slices .SortFunc (rows , func (a , b database. GetTemplateInsightsByTemplateRow ) int {
3565
- return slice .Ascending (a .TemplateID . String (), b . TemplateID .String ())
3563
+ slices .SortFunc (templateIDs , func (a , b uuid. UUID ) int {
3564
+ return slice .Ascending (a .String (), b .String ())
3566
3565
})
3567
- return rows , nil
3566
+
3567
+ // Build result
3568
+ var result []database.GetTemplateInsightsByTemplateRow
3569
+ for _ , templateID := range templateIDs {
3570
+ r := database.GetTemplateInsightsByTemplateRow {
3571
+ TemplateID : templateID ,
3572
+ }
3573
+
3574
+ uniqueUsers := map [uuid.UUID ]struct {}{}
3575
+
3576
+ for _ , mTemplateUserUsage := range appUsageByTemplateAndUser {
3577
+ mUserUsage , ok := mTemplateUserUsage [templateID ]
3578
+ if ! ok {
3579
+ continue // template was not used in this time window
3580
+ }
3581
+
3582
+ for userID , usage := range mUserUsage {
3583
+ uniqueUsers [userID ] = struct {}{}
3584
+
3585
+ r .UsageJetbrainsSeconds += usage .UsageJetbrainsSeconds
3586
+ r .UsageVscodeSeconds += usage .UsageVscodeSeconds
3587
+ r .UsageReconnectingPtySeconds += usage .UsageReconnectingPtySeconds
3588
+ r .UsageSshSeconds += usage .UsageSshSeconds
3589
+ }
3590
+ }
3591
+
3592
+ r .ActiveUsers = int64 (len (uniqueUsers ))
3593
+
3594
+ result = append (result , r )
3595
+ }
3596
+ return result , nil
3568
3597
}
3569
3598
3570
3599
func (q * FakeQuerier ) GetTemplateParameterInsights (ctx context.Context , arg database.GetTemplateParameterInsightsParams ) ([]database.GetTemplateParameterInsightsRow , error ) {
0 commit comments