@@ -3690,61 +3690,90 @@ func (q *FakeQuerier) GetTemplateInsightsByTemplate(_ context.Context, arg datab
3690
3690
q .mutex .RLock ()
3691
3691
defer q .mutex .RUnlock ()
3692
3692
3693
- /*
3694
- SELECT
3695
- template_id,
3696
- COUNT(DISTINCT user_id) AS active_users,
3697
- (SUM(usage_mins) * 60)::bigint AS usage_total_seconds, -- Includes app usage.
3698
- (SUM(ssh_mins) * 60)::bigint AS usage_ssh_seconds,
3699
- (SUM(sftp_mins) * 60)::bigint AS usage_sftp_seconds,
3700
- (SUM(reconnecting_pty_mins) * 60)::bigint AS usage_reconnecting_pty_seconds,
3701
- (SUM(vscode_mins) * 60)::bigint AS usage_vscode_seconds,
3702
- (SUM(jetbrains_mins) * 60)::bigint AS usage_jetbrains_seconds
3703
- FROM
3704
- template_usage_stats
3705
- WHERE
3706
- start_time >= @start_time::timestamptz
3707
- AND end_time <= @end_time::timestamptz
3708
- GROUP BY template_id;
3709
- */
3693
+ // map time.Time x TemplateID x UserID x <usage>
3694
+ appUsageByTemplateAndUser := map [time.Time ]map [uuid.UUID ]map [uuid.UUID ]database.GetTemplateInsightsByTemplateRow {}
3710
3695
3711
- type grouped struct {
3712
- database.GetTemplateInsightsByTemplateRow
3713
- activeUserIDs map [uuid.UUID ]struct {}
3714
- }
3715
- groupedByTemplateID := make (map [uuid.UUID ]grouped )
3716
- for _ , tus := range q .templateUsageStats {
3717
- if tus .StartTime .Before (arg .StartTime ) || tus .EndTime .After (arg .EndTime ) {
3696
+ // Review agent stats in terms of usage
3697
+ templateIDSet := make (map [uuid.UUID ]struct {})
3698
+
3699
+ for _ , s := range q .workspaceAgentStats {
3700
+ if s .CreatedAt .Before (arg .StartTime ) || s .CreatedAt .Equal (arg .EndTime ) || s .CreatedAt .After (arg .EndTime ) {
3718
3701
continue
3719
3702
}
3720
- row , ok := groupedByTemplateID [tus .TemplateID ]
3721
- if ! ok {
3722
- row = grouped {
3723
- GetTemplateInsightsByTemplateRow : database.GetTemplateInsightsByTemplateRow {
3724
- TemplateID : tus .TemplateID ,
3725
- },
3726
- activeUserIDs : make (map [uuid.UUID ]struct {}),
3727
- }
3703
+ if s .ConnectionCount == 0 {
3704
+ continue
3705
+ }
3706
+
3707
+ t := s .CreatedAt .Truncate (time .Minute )
3708
+ templateIDSet [s .TemplateID ] = struct {}{}
3709
+
3710
+ if _ , ok := appUsageByTemplateAndUser [t ]; ! ok {
3711
+ appUsageByTemplateAndUser [t ] = make (map [uuid.UUID ]map [uuid.UUID ]database.GetTemplateInsightsByTemplateRow )
3712
+ }
3713
+
3714
+ if _ , ok := appUsageByTemplateAndUser [t ][s.TemplateID ]; ! ok {
3715
+ appUsageByTemplateAndUser [t ][s.TemplateID ] = make (map [uuid.UUID ]database.GetTemplateInsightsByTemplateRow )
3716
+ }
3717
+
3718
+ if _ , ok := appUsageByTemplateAndUser [t ][s.TemplateID ][s .UserID ]; ! ok {
3719
+ appUsageByTemplateAndUser [t ][s.TemplateID ][s .UserID ] = database.GetTemplateInsightsByTemplateRow {}
3720
+ }
3721
+
3722
+ u := appUsageByTemplateAndUser [t ][s.TemplateID ][s .UserID ]
3723
+ if s .SessionCountJetBrains > 0 {
3724
+ u .UsageJetbrainsSeconds = 60
3725
+ }
3726
+ if s .SessionCountVSCode > 0 {
3727
+ u .UsageVscodeSeconds = 60
3728
+ }
3729
+ if s .SessionCountReconnectingPTY > 0 {
3730
+ u .UsageReconnectingPtySeconds = 60
3731
+ }
3732
+ if s .SessionCountSSH > 0 {
3733
+ u .UsageSshSeconds = 60
3728
3734
}
3729
- row .activeUserIDs [tus .UserID ] = struct {}{}
3730
- row .ActiveUsers = int64 (len (row .activeUserIDs ))
3731
- row .UsageTotalSeconds += int64 (tus .UsageMins ) * 60
3732
- row .UsageSshSeconds += int64 (tus .SshMins ) * 60
3733
- row .UsageSftpSeconds += int64 (tus .SftpMins ) * 60
3734
- row .UsageReconnectingPtySeconds += int64 (tus .ReconnectingPtyMins ) * 60
3735
- row .UsageVscodeSeconds += int64 (tus .VscodeMins ) * 60
3736
- row .UsageJetbrainsSeconds += int64 (tus .JetbrainsMins ) * 60
3737
- groupedByTemplateID [tus .TemplateID ] = row
3735
+ appUsageByTemplateAndUser [t ][s.TemplateID ][s .UserID ] = u
3738
3736
}
3739
3737
3740
- var rows []database.GetTemplateInsightsByTemplateRow
3741
- for _ , row := range groupedByTemplateID {
3742
- rows = append (rows , row .GetTemplateInsightsByTemplateRow )
3738
+ // Sort used templates
3739
+ templateIDs := make ([]uuid.UUID , 0 , len (templateIDSet ))
3740
+ for templateID := range templateIDSet {
3741
+ templateIDs = append (templateIDs , templateID )
3743
3742
}
3744
- slices .SortFunc (rows , func (a , b database. GetTemplateInsightsByTemplateRow ) int {
3745
- return slice .Ascending (a .TemplateID . String (), b . TemplateID .String ())
3743
+ slices .SortFunc (templateIDs , func (a , b uuid. UUID ) int {
3744
+ return slice .Ascending (a .String (), b .String ())
3746
3745
})
3747
- return rows , nil
3746
+
3747
+ // Build result
3748
+ var result []database.GetTemplateInsightsByTemplateRow
3749
+ for _ , templateID := range templateIDs {
3750
+ r := database.GetTemplateInsightsByTemplateRow {
3751
+ TemplateID : templateID ,
3752
+ }
3753
+
3754
+ uniqueUsers := map [uuid.UUID ]struct {}{}
3755
+
3756
+ for _ , mTemplateUserUsage := range appUsageByTemplateAndUser {
3757
+ mUserUsage , ok := mTemplateUserUsage [templateID ]
3758
+ if ! ok {
3759
+ continue // template was not used in this time window
3760
+ }
3761
+
3762
+ for userID , usage := range mUserUsage {
3763
+ uniqueUsers [userID ] = struct {}{}
3764
+
3765
+ r .UsageJetbrainsSeconds += usage .UsageJetbrainsSeconds
3766
+ r .UsageVscodeSeconds += usage .UsageVscodeSeconds
3767
+ r .UsageReconnectingPtySeconds += usage .UsageReconnectingPtySeconds
3768
+ r .UsageSshSeconds += usage .UsageSshSeconds
3769
+ }
3770
+ }
3771
+
3772
+ r .ActiveUsers = int64 (len (uniqueUsers ))
3773
+
3774
+ result = append (result , r )
3775
+ }
3776
+ return result , nil
3748
3777
}
3749
3778
3750
3779
func (q * FakeQuerier ) GetTemplateParameterInsights (ctx context.Context , arg database.GetTemplateParameterInsightsParams ) ([]database.GetTemplateParameterInsightsRow , error ) {
0 commit comments