Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -52,3 +52,4 @@ claws.log
# Node.js
node_modules/
.claude
.gtrconfig
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -395,6 +395,7 @@ timeouts:
multi_region_fetch: 60s # Multi-region parallel fetch timeout (default: 30s)
tag_search: 45s # Tag search timeout (default: 30s)
metrics_load: 30s # CloudWatch metrics load timeout (default: 30s)
log_fetch: 15s # CloudWatch Logs fetch timeout (default: 10s)

concurrency:
max_fetches: 100 # Max concurrent API fetches (default: 50)
Expand Down
5 changes: 3 additions & 2 deletions custom/autoscaling/groups/render.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import (

"github.com/clawscli/claws/internal/dao"
"github.com/clawscli/claws/internal/render"
"github.com/clawscli/claws/internal/ui"
)

// AutoScalingGroupRenderer renders Auto Scaling Groups
Expand Down Expand Up @@ -192,9 +193,9 @@ func (r *AutoScalingGroupRenderer) RenderDetail(resource dao.Resource) string {
}
if proc.ProcessName != nil {
if reason != "" {
d.FieldStyled(*proc.ProcessName, reason, render.WarningStyle())
d.FieldStyled(*proc.ProcessName, reason, ui.WarningStyle())
} else {
d.FieldStyled(*proc.ProcessName, "Suspended", render.WarningStyle())
d.FieldStyled(*proc.ProcessName, "Suspended", ui.WarningStyle())
}
}
}
Expand Down
9 changes: 5 additions & 4 deletions custom/cloudformation/events/render.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import (

"github.com/clawscli/claws/internal/dao"
"github.com/clawscli/claws/internal/render"
"github.com/clawscli/claws/internal/ui"
)

// EventRenderer renders CloudFormation stack events
Expand Down Expand Up @@ -140,13 +141,13 @@ func (r *EventRenderer) RenderSummary(resource dao.Resource) []render.SummaryFie
func cfnResourceStatusColorer(status string) render.Style {
switch {
case strings.HasSuffix(status, "_COMPLETE") && !strings.Contains(status, "ROLLBACK") && !strings.Contains(status, "DELETE"):
return render.SuccessStyle()
return ui.SuccessStyle()
case strings.Contains(status, "IN_PROGRESS"):
return render.WarningStyle()
return ui.WarningStyle()
case strings.Contains(status, "FAILED") || strings.Contains(status, "ROLLBACK"):
return render.DangerStyle()
return ui.DangerStyle()
case strings.Contains(status, "DELETE_COMPLETE") || strings.Contains(status, "SKIPPED"):
return render.DimStyle()
return ui.DimStyle()
default:
return render.DefaultStyle()
}
Expand Down
15 changes: 8 additions & 7 deletions custom/cloudformation/resources/render.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import (
"github.com/clawscli/claws/internal/dao"
"github.com/clawscli/claws/internal/registry"
"github.com/clawscli/claws/internal/render"
"github.com/clawscli/claws/internal/ui"
)

// Ensure ResourceRenderer implements render.Navigator
Expand Down Expand Up @@ -148,13 +149,13 @@ func (r *ResourceRenderer) RenderSummary(resource dao.Resource) []render.Summary
func cfnResourceStatusColorer(status string) render.Style {
switch {
case strings.HasSuffix(status, "_COMPLETE") && !strings.Contains(status, "ROLLBACK") && !strings.Contains(status, "DELETE"):
return render.SuccessStyle()
return ui.SuccessStyle()
case strings.Contains(status, "IN_PROGRESS"):
return render.WarningStyle()
return ui.WarningStyle()
case strings.Contains(status, "FAILED") || strings.Contains(status, "ROLLBACK"):
return render.DangerStyle()
return ui.DangerStyle()
case strings.Contains(status, "DELETE_COMPLETE") || strings.Contains(status, "SKIPPED"):
return render.DimStyle()
return ui.DimStyle()
default:
return render.DefaultStyle()
}
Expand All @@ -164,11 +165,11 @@ func cfnResourceStatusColorer(status string) render.Style {
func driftColorer(status string) render.Style {
switch status {
case "IN_SYNC":
return render.SuccessStyle()
return ui.SuccessStyle()
case "MODIFIED", "DELETED":
return render.DangerStyle()
return ui.DangerStyle()
case "NOT_CHECKED":
return render.DimStyle()
return ui.DimStyle()
default:
return render.DefaultStyle()
}
Expand Down
15 changes: 8 additions & 7 deletions custom/cloudformation/stacks/render.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import (
appaws "github.com/clawscli/claws/internal/aws"
"github.com/clawscli/claws/internal/dao"
"github.com/clawscli/claws/internal/render"
"github.com/clawscli/claws/internal/ui"
)

// Ensure StackRenderer implements render.Navigator
Expand Down Expand Up @@ -244,13 +245,13 @@ func (r *StackRenderer) RenderSummary(resource dao.Resource) []render.SummaryFie
func cfnStateColorer(status string) render.Style {
switch {
case strings.HasSuffix(status, "_COMPLETE") && !strings.Contains(status, "ROLLBACK") && !strings.Contains(status, "DELETE"):
return render.SuccessStyle()
return ui.SuccessStyle()
case strings.Contains(status, "IN_PROGRESS"):
return render.WarningStyle()
return ui.WarningStyle()
case strings.Contains(status, "FAILED") || strings.Contains(status, "ROLLBACK"):
return render.DangerStyle()
return ui.DangerStyle()
case strings.Contains(status, "DELETE_COMPLETE"):
return render.DimStyle()
return ui.DimStyle()
default:
return render.DefaultStyle()
}
Expand All @@ -260,11 +261,11 @@ func cfnStateColorer(status string) render.Style {
func driftColorer(status string) render.Style {
switch status {
case "IN_SYNC":
return render.SuccessStyle()
return ui.SuccessStyle()
case "DRIFTED":
return render.DangerStyle()
return ui.DangerStyle()
case "NOT_CHECKED":
return render.DimStyle()
return ui.DimStyle()
default:
return render.DefaultStyle()
}
Expand Down
5 changes: 3 additions & 2 deletions custom/cloudfront/distributions/render.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import (

"github.com/clawscli/claws/internal/dao"
"github.com/clawscli/claws/internal/render"
"github.com/clawscli/claws/internal/ui"
)

// DistributionRenderer renders CloudFront distributions
Expand Down Expand Up @@ -165,15 +166,15 @@ func (r *DistributionRenderer) RenderDetail(resource dao.Resource) string {
d.Field("Price Class", dist.PriceClass())
d.Field("HTTP Version", dist.HttpVersion())
if dist.IsIPV6Enabled {
d.FieldStyled("IPv6", "Enabled", render.SuccessStyle())
d.FieldStyled("IPv6", "Enabled", ui.SuccessStyle())
} else {
d.Field("IPv6", "Disabled")
}

// Access Logging
if dist.Logging != nil && dist.Logging.Enabled != nil && *dist.Logging.Enabled {
d.Section("Access Logging")
d.FieldStyled("Status", "Enabled", render.SuccessStyle())
d.FieldStyled("Status", "Enabled", ui.SuccessStyle())
if dist.Logging.Bucket != nil {
d.Field("Bucket", *dist.Logging.Bucket)
}
Expand Down
18 changes: 0 additions & 18 deletions custom/cloudwatch/log-groups/actions.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,24 +13,6 @@ import (

func init() {
action.Global.Register("cloudwatch", "log-groups", []action.Action{
{
Name: action.ActionNameTailLogs,
Shortcut: "t",
Type: action.ActionTypeExec,
Command: `aws logs tail "${ID}" --since 1h --follow`,
},
{
Name: action.ActionNameViewRecent1h,
Shortcut: "1",
Type: action.ActionTypeExec,
Command: `aws logs tail "${ID}" --since 1h | less -R`,
},
{
Name: action.ActionNameViewRecent24h,
Shortcut: "2",
Type: action.ActionTypeExec,
Command: `aws logs tail "${ID}" --since 24h | less -R`,
},
{
Name: "Delete",
Shortcut: "D",
Expand Down
20 changes: 12 additions & 8 deletions custom/cloudwatch/log-groups/render.go
Original file line number Diff line number Diff line change
Expand Up @@ -34,14 +34,14 @@ func NewLogGroupRenderer() render.Renderer {
}

func getSize(r dao.Resource) string {
if lg, ok := r.(*LogGroupResource); ok {
if lg, ok := dao.UnwrapResource(r).(*LogGroupResource); ok {
return render.FormatSize(lg.StoredBytes())
}
return "-"
}

func getRetention(r dao.Resource) string {
if lg, ok := r.(*LogGroupResource); ok {
if lg, ok := dao.UnwrapResource(r).(*LogGroupResource); ok {
days := lg.RetentionDays()
if days == 0 {
return "Never"
Expand All @@ -55,7 +55,7 @@ func getRetention(r dao.Resource) string {
}

func getClass(r dao.Resource) string {
if lg, ok := r.(*LogGroupResource); ok {
if lg, ok := dao.UnwrapResource(r).(*LogGroupResource); ok {
class := lg.LogGroupClass()
if class == "" || class == "STANDARD" {
return "Standard"
Expand All @@ -66,7 +66,7 @@ func getClass(r dao.Resource) string {
}

func getAge(r dao.Resource) string {
if lg, ok := r.(*LogGroupResource); ok {
if lg, ok := dao.UnwrapResource(r).(*LogGroupResource); ok {
creationTime := lg.CreationTime()
if creationTime > 0 {
t := time.UnixMilli(creationTime)
Expand All @@ -78,7 +78,7 @@ func getAge(r dao.Resource) string {

// RenderDetail renders detailed log group information
func (r *LogGroupRenderer) RenderDetail(resource dao.Resource) string {
lg, ok := resource.(*LogGroupResource)
lg, ok := dao.UnwrapResource(resource).(*LogGroupResource)
if !ok {
return ""
}
Expand Down Expand Up @@ -138,7 +138,7 @@ func (r *LogGroupRenderer) RenderDetail(resource dao.Resource) string {

// RenderSummary returns summary fields for the header panel
func (r *LogGroupRenderer) RenderSummary(resource dao.Resource) []render.SummaryField {
lg, ok := resource.(*LogGroupResource)
lg, ok := dao.UnwrapResource(resource).(*LogGroupResource)
if !ok {
return r.BaseRenderer.RenderSummary(resource)
}
Expand Down Expand Up @@ -172,14 +172,18 @@ func (r *LogGroupRenderer) RenderSummary(resource dao.Resource) []render.Summary
return fields
}

// Navigations returns navigation shortcuts
func (r *LogGroupRenderer) Navigations(resource dao.Resource) []render.Navigation {
lg, ok := resource.(*LogGroupResource)
lg, ok := dao.UnwrapResource(resource).(*LogGroupResource)
if !ok {
return nil
}

return []render.Navigation{
{
Key: "t",
Label: "Tail",
ViewType: render.ViewTypeLogView,
},
{
Key: "s",
Label: "Streams",
Expand Down
29 changes: 2 additions & 27 deletions custom/cloudwatch/log-streams/actions.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,26 +12,7 @@ import (
)

func init() {
// Register actions for CloudWatch Log Streams
action.Global.Register("cloudwatch", "log-streams", []action.Action{
{
Name: action.ActionNameTailLogs,
Shortcut: "t",
Type: action.ActionTypeExec,
Command: `aws logs tail "${LOG_GROUP}" --log-stream-names "${NAME}" --since 1h --follow`,
},
{
Name: action.ActionNameViewRecent1h,
Shortcut: "1",
Type: action.ActionTypeExec,
Command: `aws logs tail "${LOG_GROUP}" --log-stream-names "${NAME}" --since 1h | less -R`,
},
{
Name: action.ActionNameViewRecent24h,
Shortcut: "2",
Type: action.ActionTypeExec,
Command: `aws logs tail "${LOG_GROUP}" --log-stream-names "${NAME}" --since 24h | less -R`,
},
{
Name: "Delete",
Shortcut: "D",
Expand All @@ -41,11 +22,9 @@ func init() {
},
})

// Register executor
action.RegisterExecutor("cloudwatch", "log-streams", executeLogStreamAction)
}

// executeLogStreamAction executes an action on a CloudWatch Log Stream
func executeLogStreamAction(ctx context.Context, act action.Action, resource dao.Resource) action.ActionResult {
switch act.Operation {
case "DeleteLogStream":
Expand All @@ -55,17 +34,13 @@ func executeLogStreamAction(ctx context.Context, act action.Action, resource dao
}
}

func getCloudWatchLogsClient(ctx context.Context) (*cloudwatchlogs.Client, error) {
return cwClient.GetLogsClient(ctx)
}

func executeDeleteLogStream(ctx context.Context, resource dao.Resource) action.ActionResult {
ls, ok := resource.(*LogStreamResource)
ls, ok := dao.UnwrapResource(resource).(*LogStreamResource)
if !ok {
return action.InvalidResourceResult()
}

client, err := getCloudWatchLogsClient(ctx)
client, err := cwClient.GetLogsClient(ctx)
if err != nil {
return action.ActionResult{Success: false, Error: err}
}
Expand Down
3 changes: 3 additions & 0 deletions custom/cloudwatch/log-streams/dao.go
Original file line number Diff line number Diff line change
Expand Up @@ -117,6 +117,9 @@ func (d *LogStreamDAO) Delete(ctx context.Context, id string) error {

_, err := d.client.DeleteLogStream(ctx, input)
if err != nil {
if apperrors.IsNotFound(err) {
return nil
}
return apperrors.Wrapf(err, "delete log stream %s", id)
}

Expand Down
16 changes: 10 additions & 6 deletions custom/cloudwatch/log-streams/render.go
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ func NewLogStreamRenderer() render.Renderer {
}

func getLastEvent(r dao.Resource) string {
if ls, ok := r.(*LogStreamResource); ok {
if ls, ok := dao.UnwrapResource(r).(*LogStreamResource); ok {
lastEvent := ls.LastEventTimestamp()
if lastEvent > 0 {
t := time.UnixMilli(lastEvent)
Expand All @@ -42,7 +42,7 @@ func getLastEvent(r dao.Resource) string {
}

func getAge(r dao.Resource) string {
if ls, ok := r.(*LogStreamResource); ok {
if ls, ok := dao.UnwrapResource(r).(*LogStreamResource); ok {
creationTime := ls.CreationTime()
if creationTime > 0 {
t := time.UnixMilli(creationTime)
Expand All @@ -54,7 +54,7 @@ func getAge(r dao.Resource) string {

// RenderDetail renders detailed log stream information
func (r *LogStreamRenderer) RenderDetail(resource dao.Resource) string {
ls, ok := resource.(*LogStreamResource)
ls, ok := dao.UnwrapResource(resource).(*LogStreamResource)
if !ok {
return ""
}
Expand Down Expand Up @@ -95,7 +95,7 @@ func (r *LogStreamRenderer) RenderDetail(resource dao.Resource) string {

// RenderSummary returns summary fields for the header panel
func (r *LogStreamRenderer) RenderSummary(resource dao.Resource) []render.SummaryField {
ls, ok := resource.(*LogStreamResource)
ls, ok := dao.UnwrapResource(resource).(*LogStreamResource)
if !ok {
return r.BaseRenderer.RenderSummary(resource)
}
Expand All @@ -118,14 +118,18 @@ func (r *LogStreamRenderer) RenderSummary(resource dao.Resource) []render.Summar
return fields
}

// Navigations returns navigation shortcuts
func (r *LogStreamRenderer) Navigations(resource dao.Resource) []render.Navigation {
ls, ok := resource.(*LogStreamResource)
ls, ok := dao.UnwrapResource(resource).(*LogStreamResource)
if !ok {
return nil
}

return []render.Navigation{
{
Key: "t",
Label: "Tail",
ViewType: render.ViewTypeLogView,
},
{
Key: "g",
Label: "Log Group",
Expand Down
Loading