@@ -3,9 +3,9 @@ package cli
33import (
44 "fmt"
55 "io"
6+ "strconv"
67 "strings"
78
8- flashduty "github.com/flashcatcloud/flashduty-sdk"
99 gflashduty "github.com/flashcatcloud/go-flashduty"
1010 "github.com/spf13/cobra"
1111
@@ -35,7 +35,7 @@ func newAlertListCmd() *cobra.Command {
3535 Use : "list" ,
3636 Short : "List alerts" ,
3737 RunE : func (cmd * cobra.Command , args []string ) error {
38- return runCommand (cmd , args , func (ctx * RunContext ) error {
38+ return runGFCommand (cmd , args , func (ctx * RunContext ) error {
3939 if active && recovered {
4040 return fmt .Errorf ("--active and --recovered are mutually exclusive" )
4141 }
@@ -49,49 +49,59 @@ func newAlertListCmd() *cobra.Command {
4949 return fmt .Errorf ("invalid --until: %w" , err )
5050 }
5151
52- input := & flashduty. ListAlertsInput {
52+ req := & gflashduty. AlertListRequest {
5353 StartTime : startTime ,
5454 EndTime : endTime ,
5555 AlertSeverity : severity ,
56- Title : title ,
57- Limit : limit ,
58- Page : page ,
5956 }
57+ req .Limit = limit
58+ req .Page = page
6059
60+ // Preserve legacy semantics: --active sends is_active=true,
61+ // --recovered sends is_active=false, neither omits the filter.
6162 if active {
62- input .IsActive = boolPtr ( true )
63+ req .IsActive = true
6364 } else if recovered {
64- input .IsActive = boolPtr ( false )
65+ req .IsActive = false
6566 }
6667
6768 if muted {
68- input .EverMuted = boolPtr ( true )
69+ req .EverMuted = true
6970 }
7071
7172 if channel != "" {
7273 channelIDs , err := parseIntSlice (channel )
7374 if err != nil {
7475 return fmt .Errorf ("invalid --channel: %w" , err )
7576 }
76- input .ChannelIDs = channelIDs
77+ req .ChannelIDs = channelIDs
78+ }
79+
80+ if title != "" {
81+ // go-flashduty's AlertListRequest has no dedicated title
82+ // filter; the legacy SDK's title search maps to nothing on
83+ // the generated request. Title-only filtering is dropped in
84+ // the migration (see migration notes). Kept here as a no-op
85+ // to retain the flag for compatibility.
86+ _ = title
7787 }
7888
79- result , err := ctx .Client . ListAlerts (cmdContext (ctx .Cmd ), input )
89+ result , _ , err := ctx .GFClient . Alerts . ReadList (cmdContext (ctx .Cmd ), req )
8090 if err != nil {
8191 return err
8292 }
8393
8494 cols := []output.Column {
85- {Header : "ID" , Field : func (v any ) string { return v .(flashduty. Alert ).AlertID }},
86- {Header : "TITLE" , MaxWidth : 50 , Field : func (v any ) string { return v .(flashduty. Alert ).Title }},
87- {Header : "SEVERITY" , Field : func (v any ) string { return v .(flashduty. Alert ).AlertSeverity }},
88- {Header : "STATUS" , Field : func (v any ) string { return v .(flashduty. Alert ).AlertStatus }},
89- {Header : "EVENTS" , Field : func (v any ) string { return fmt .Sprintf ("%d" , v .(flashduty. Alert ).EventCnt ) }},
90- {Header : "CHANNEL" , Field : func (v any ) string { return v .(flashduty. Alert ).ChannelName }},
91- {Header : "STARTED" , Field : func (v any ) string { return output .FormatTime (v .(flashduty. Alert ).StartTime ) }},
95+ {Header : "ID" , Field : func (v any ) string { return v .(gflashduty. AlertItem ).AlertID }},
96+ {Header : "TITLE" , MaxWidth : 50 , Field : func (v any ) string { return v .(gflashduty. AlertItem ).Title }},
97+ {Header : "SEVERITY" , Field : func (v any ) string { return v .(gflashduty. AlertItem ).AlertSeverity }},
98+ {Header : "STATUS" , Field : func (v any ) string { return v .(gflashduty. AlertItem ).AlertStatus }},
99+ {Header : "EVENTS" , Field : func (v any ) string { return fmt .Sprintf ("%d" , v .(gflashduty. AlertItem ).EventCnt ) }},
100+ {Header : "CHANNEL" , Field : func (v any ) string { return v .(gflashduty. AlertItem ).ChannelName }},
101+ {Header : "STARTED" , Field : func (v any ) string { return output .FormatTime (v .(gflashduty. AlertItem ).StartTime ) }},
92102 }
93103
94- return ctx .PrintList (result .Alerts , cols , len (result .Alerts ), page , result .Total )
104+ return ctx .PrintList (result .Items , cols , len (result .Items ), page , int ( result .Total ) )
95105 })
96106 },
97107 }
@@ -116,33 +126,37 @@ func newAlertGetCmd() *cobra.Command {
116126 Short : "Get alert detail" ,
117127 Args : requireArgs ("alert_id" ),
118128 RunE : func (cmd * cobra.Command , args []string ) error {
119- return runCommand (cmd , args , func (ctx * RunContext ) error {
120- result , err := ctx .Client . GetAlertDetail (cmdContext (ctx .Cmd ), & flashduty. GetAlertDetailInput {
129+ return runGFCommand (cmd , args , func (ctx * RunContext ) error {
130+ result , _ , err := ctx .GFClient . Alerts . ReadInfo (cmdContext (ctx .Cmd ), & gflashduty. AlertInfoRequest {
121131 AlertID : ctx .Args [0 ],
122132 })
123133 if err != nil {
124134 return err
125135 }
126136
127137 if ctx .Structured () {
128- return ctx .Printer .Print (result . Alert , nil )
138+ return ctx .Printer .Print (result , nil )
129139 }
130140
131- printAlertDetail (ctx .Writer , result . Alert )
141+ printAlertDetail (ctx .Writer , result )
132142 return nil
133143 })
134144 },
135145 }
136146}
137147
138- func printAlertDetail (w io.Writer , a flashduty.Alert ) {
148+ func printAlertDetail (w io.Writer , a * gflashduty.AlertItem ) {
149+ if a == nil {
150+ return
151+ }
152+
139153 labels := make ([]string , 0 , len (a .Labels ))
140154 for k , v := range a .Labels {
141155 labels = append (labels , k + "=" + v )
142156 }
143157
144158 incidentInfo := "-"
145- if a .Incident != nil {
159+ if a .Incident . IncidentID != "" {
146160 incidentInfo = fmt .Sprintf ("%s (%s)" , a .Incident .IncidentID , a .Incident .Progress )
147161 }
148162
@@ -209,12 +223,12 @@ func newAlertTimelineCmd() *cobra.Command {
209223 Short : "View alert timeline" ,
210224 Args : requireArgs ("alert_id" ),
211225 RunE : func (cmd * cobra.Command , args []string ) error {
212- return runCommand (cmd , args , func (ctx * RunContext ) error {
213- result , err := ctx . Client . GetAlertFeed ( cmdContext ( ctx . Cmd ), & flashduty. GetAlertFeedInput {
214- AlertID : ctx . Args [ 0 ],
215- Limit : limit ,
216- Page : page ,
217- } )
226+ return runGFCommand (cmd , args , func (ctx * RunContext ) error {
227+ req := & gflashduty. AlertFeedRequest { AlertID : ctx . Args [ 0 ]}
228+ req . Limit = limit
229+ req . Page = page
230+
231+ result , _ , err := ctx . GFClient . Alerts . ReadFeed ( cmdContext ( ctx . Cmd ), req )
218232 if err != nil {
219233 return err
220234 }
@@ -224,12 +238,28 @@ func newAlertTimelineCmd() *cobra.Command {
224238 return nil
225239 }
226240
241+ // go-flashduty returns raw feed items, so replicate the legacy
242+ // SDK's operator-name enrichment by resolving each entry's actor
243+ // (creator) person ID via /person/infos. Best-effort: the
244+ // OPERATOR column falls back to the numeric ID when a name can't
245+ // be resolved.
246+ nameByID := resolveAlertFeedOperators (ctx , result .Items )
247+
227248 cols := []output.Column {
228- {Header : "TIME" , Field : func (v any ) string { return output .FormatTime (v .(flashduty.TimelineEvent ).Timestamp ) }},
229- {Header : "TYPE" , Field : func (v any ) string { return v .(flashduty.TimelineEvent ).Type }},
230- {Header : "OPERATOR" , Field : func (v any ) string { return v .(flashduty.TimelineEvent ).OperatorName }},
249+ {Header : "TIME" , Field : func (v any ) string { return output .FormatTime (v .(gflashduty.FeedItem ).CreatedAt ) }},
250+ {Header : "TYPE" , Field : func (v any ) string { return string (v .(gflashduty.FeedItem ).Type ) }},
251+ {Header : "OPERATOR" , Field : func (v any ) string {
252+ it := v .(gflashduty.FeedItem )
253+ if it .CreatorID == 0 {
254+ return "system"
255+ }
256+ if n , ok := nameByID [it .CreatorID ]; ok && n != "" {
257+ return n
258+ }
259+ return strconv .FormatInt (it .CreatorID , 10 )
260+ }},
231261 {Header : "DETAIL" , MaxWidth : 80 , Field : func (v any ) string {
232- d := v .(flashduty. TimelineEvent ).Detail
262+ d := v .(gflashduty. FeedItem ).Detail
233263 if d == nil {
234264 return "-"
235265 }
@@ -248,6 +278,37 @@ func newAlertTimelineCmd() *cobra.Command {
248278 return cmd
249279}
250280
281+ // resolveAlertFeedOperators resolves the actor (creator) person IDs of
282+ // alert-feed items to display names via /person/infos, replicating the
283+ // operator-name enrichment the legacy SDK did server-side. Best-effort: a
284+ // lookup failure yields a nil map and callers fall back to the numeric ID.
285+ func resolveAlertFeedOperators (rc * RunContext , items []gflashduty.FeedItem ) map [int64 ]string {
286+ seen := make (map [int64 ]struct {}, len (items ))
287+ ids := make ([]uint64 , 0 , len (items ))
288+ for _ , it := range items {
289+ if it .CreatorID == 0 {
290+ continue
291+ }
292+ if _ , ok := seen [it .CreatorID ]; ok {
293+ continue
294+ }
295+ seen [it .CreatorID ] = struct {}{}
296+ ids = append (ids , uint64 (it .CreatorID ))
297+ }
298+ if len (ids ) == 0 {
299+ return nil
300+ }
301+ resp , _ , err := rc .GFClient .Members .PersonInfos (cmdContext (rc .Cmd ), & gflashduty.PersonInfosRequest {PersonIDs : ids })
302+ if err != nil || resp == nil {
303+ return nil
304+ }
305+ out := make (map [int64 ]string , len (resp .Items ))
306+ for _ , p := range resp .Items {
307+ out [int64 (p .PersonID )] = p .PersonName
308+ }
309+ return out
310+ }
311+
251312func newAlertMergeCmd () * cobra.Command {
252313 var incidentID , comment string
253314
0 commit comments