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
160 changes: 19 additions & 141 deletions internal/app/app.go
Original file line number Diff line number Diff line change
Expand Up @@ -129,43 +129,6 @@ type Model struct {
// SSM session state
selectedInstance *awsservice.EC2Instance

// VPC browser state
vpcs []awsservice.VPC
filteredVPCs []awsservice.VPC
vpcIdx int
subnets []awsservice.Subnet
filteredSubnets []awsservice.Subnet
subnetIdx int
selectedVPC *awsservice.VPC
selectedSubnet *awsservice.Subnet
availableIPs []string
filteredIPs []string
ipScrollOffset int
ipFilter string
ipFilterActive bool
reachabilityRegions []string
filteredReachabilityRegions []string
reachabilityRegion string
reachabilityRegionIdx int
reachabilityRegionFilter string
reachabilityRegionFiltering bool
reachabilityTargets []awsservice.ReachabilityTarget
filteredReachabilityTargets []awsservice.ReachabilityTarget
reachabilitySourceTypes []string
reachabilitySourceTypeIdx int
reachabilityDestTypes []string
reachabilityDestTypeIdx int
reachabilityIdx int
reachabilityFilter string
reachabilityFilterActive bool
reachabilitySource *awsservice.ReachabilityTarget
reachabilityDestination *awsservice.ReachabilityTarget
reachabilityDestinationIP string
reachabilityProtocolIdx int
reachabilityPortInput string
reachabilityConfigField int
reachabilityResult *awsservice.ReachabilityAnalysisResult
reachabilityScrollOffset int
// Security Group browser state
securityGroups []awsservice.SecurityGroup
filteredSecurityGroups []awsservice.SecurityGroup
Expand All @@ -180,26 +143,6 @@ type Model struct {
sgAddInput string // current field text input
sgAddSelectIdx int // index for select-type fields (direction, protocol)

// ECS browser state
ecsClusters []awsservice.ECSCluster
filteredECSClusters []awsservice.ECSCluster
ecsClusterIdx int
selectedECSCluster *awsservice.ECSCluster

ecsServices []awsservice.ECSService
filteredECSServices []awsservice.ECSService
ecsServiceIdx int
selectedECSService *awsservice.ECSService
selectedECSDetail *awsservice.ECSServiceDetail
ecsDetailScroll int

ecsTasks []awsservice.ECSTask
ecsTaskIdx int
selectedECSTask *awsservice.ECSTask

ecsContainers []awsservice.ECSContainer
ecsContainerIdx int

// EKS browser state
eksClusters []awsservice.EKSCluster
filteredEKSClusters []awsservice.EKSCluster
Expand Down Expand Up @@ -230,16 +173,19 @@ type Model struct {
ecrCopyMsg string

// Feature submodels
ec2Browser ec2InstanceBrowserModel
cwMetrics cloudWatchMetricsModel
cwLogs cloudWatchLogsModel
rds rdsModel
route53 route53Model
iam iamModel
bedrock bedrockModel
secrets secretsModel
s3 s3Model
lambda lambdaModel
ec2Browser ec2InstanceBrowserModel
ecs ecsModel
vpc vpcModel
reachability reachabilityModel
cwMetrics cloudWatchMetricsModel
cwLogs cloudWatchLogsModel
rds rdsModel
route53 route53Model
iam iamModel
bedrock bedrockModel
secrets secretsModel
s3 s3Model
lambda lambdaModel

// Inspector browser state
inspectorWorkflows []inspector.Workflow
Expand Down Expand Up @@ -339,6 +285,9 @@ func New(cfg *config.Config, configPath string, version string, checklistPath ..
contextTable: newContextTable(),
}
model.ec2Browser = newEC2InstanceBrowserModel()
model.ecs = newECSModel()
model.vpc = newVPCModel()
model.reachability = newReachabilityModel()
model.cwMetrics = newCloudWatchMetricsModel()
model.cwLogs = newCloudWatchLogsModel()
model.rds = newRDSModel()
Expand Down Expand Up @@ -445,7 +394,6 @@ func (m Model) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
for _, h := range []func(tea.Msg) (tea.Model, tea.Cmd, bool){
m.handleEC2VPCMsg,
m.handleSecurityGroupMsg,
m.handleECSMsg,
m.handleEKSMsg,
m.handleECRMsg,
m.handleInspectorMsg,
Expand Down Expand Up @@ -515,22 +463,6 @@ func (m Model) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
return m.updateFeatureList(msg)
case screenInstanceList:
return m.updateInstanceList(msg)
case screenVPCList:
return m.updateVPCList(msg)
case screenSubnetList:
return m.updateSubnetList(msg)
case screenSubnetDetail:
return m.updateSubnetDetail(msg)
case screenReachabilityRegionList:
return m.updateReachabilityRegionList(msg)
case screenReachabilitySourceList:
return m.updateReachabilitySourceList(msg)
case screenReachabilityDestinationList:
return m.updateReachabilityDestinationList(msg)
case screenReachabilityConfig:
return m.updateReachabilityConfig(msg)
case screenReachabilityResult:
return m.updateReachabilityResult(msg)
case screenInspectorHome:
return m.updateInspectorHome(msg)
case screenInspectorWorkflowPlaceholder:
Expand All @@ -553,16 +485,6 @@ func (m Model) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
return m.updateSecurityGroupAddRule(msg)
case screenSecurityGroupDeleteConfirm:
return m.updateSecurityGroupDeleteConfirm(msg)
case screenECSClusterList:
return m.updateECSClusterList(msg)
case screenECSServiceList:
return m.updateECSServiceList(msg)
case screenECSServiceDetail:
return m.updateECSServiceDetail(msg)
case screenECSTaskList:
return m.updateECSTaskList(msg)
case screenECSContainerList:
return m.updateECSContainerList(msg)
case screenEKSClusterList:
return m.updateEKSClusterList(msg)
case screenEKSNodeGroupList:
Expand Down Expand Up @@ -660,27 +582,9 @@ func (m Model) updateFeatureList(msg tea.KeyMsg) (tea.Model, tea.Cmd) {
case domain.FeatureEC2InstanceBrowser:
return m.ec2Browser.Start(&m)
case domain.FeatureVPCBrowser:
return m.startLoading(m.loadVPCs())
return m.vpc.Start(&m)
case domain.FeatureReachabilityAnalyzer:
m.reachabilityRegions = availableReachabilityRegions(m.cfg.Region)
m.filteredReachabilityRegions = m.reachabilityRegions
m.reachabilityRegion = m.cfg.Region
m.reachabilityRegionIdx = indexOfString(m.reachabilityRegions, m.reachabilityRegion)
if m.reachabilityRegionIdx < 0 {
m.reachabilityRegionIdx = 0
}
m.reachabilityRegionFilter = ""
m.reachabilityRegionFiltering = false
m.reachabilityTargets = nil
m.filteredReachabilityTargets = nil
m.reachabilitySource = nil
m.reachabilityDestination = nil
m.reachabilityDestinationIP = ""
m.reachabilityResult = nil
m.reachabilityScrollOffset = 0
m.awsRepo = nil
m.screen = screenReachabilityRegionList
return m, nil
return m.reachability.Start(&m)
case domain.FeatureRDSBrowser:
return m.rds.Start(&m)
case domain.FeatureRoute53Browser:
Expand All @@ -702,7 +606,7 @@ func (m Model) updateFeatureList(msg tea.KeyMsg) (tea.Model, tea.Cmd) {
case domain.FeatureRotateAccessKey:
return m.iam.StartKeys(&m, true)
case domain.FeatureECSExec:
return m.startLoading(m.loadECSClusters())
return m.ecs.Start(&m)
case domain.FeatureECRRepositoryBrowser:
return m.startLoading(m.loadECRRepositories())
case domain.FeatureEKSBrowser:
Expand Down Expand Up @@ -751,22 +655,6 @@ func (m Model) View() string {
v = m.viewFeatureList()
case screenInstanceList:
v = m.viewInstanceList()
case screenVPCList:
v = m.viewVPCList()
case screenSubnetList:
v = m.viewSubnetList()
case screenSubnetDetail:
v = m.viewSubnetDetail()
case screenReachabilityRegionList:
v = m.viewReachabilityRegionList()
case screenReachabilitySourceList:
v = m.viewReachabilitySourceList()
case screenReachabilityDestinationList:
v = m.viewReachabilityDestinationList()
case screenReachabilityConfig:
v = m.viewReachabilityConfig()
case screenReachabilityResult:
v = m.viewReachabilityResult()
case screenInspectorHome:
v = m.viewInspectorHome()
case screenInspectorWorkflowPlaceholder:
Expand All @@ -791,16 +679,6 @@ func (m Model) View() string {
v = m.viewSecurityGroupAddRule()
case screenSecurityGroupDeleteConfirm:
v = m.viewSecurityGroupDeleteConfirm()
case screenECSClusterList:
v = m.viewECSClusterList()
case screenECSServiceList:
v = m.viewECSServiceList()
case screenECSServiceDetail:
v = m.viewECSServiceDetail()
case screenECSTaskList:
v = m.viewECSTaskList()
case screenECSContainerList:
v = m.viewECSContainerList()
case screenEKSClusterList:
v = m.viewEKSClusterList()
case screenEKSNodeGroupList:
Expand Down
40 changes: 20 additions & 20 deletions internal/app/app_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -486,15 +486,15 @@ func TestReachabilityFeatureOpensRegionSelection(t *testing.T) {
if model.screen != screenReachabilityRegionList {
t.Fatalf("expected region selection screen, got %v", model.screen)
}
if model.reachabilityRegion != "us-east-1" {
t.Fatalf("expected default reachability region us-east-1, got %q", model.reachabilityRegion)
if model.reachability.region != "us-east-1" {
t.Fatalf("expected default reachability region us-east-1, got %q", model.reachability.region)
}
}

func TestReachabilityStatusBarUsesOverrideRegion(t *testing.T) {
m := New(testConfig(), "", "dev")
m.screen = screenReachabilitySourceList
m.reachabilityRegion = "ap-northeast-2"
m.reachability.region = "ap-northeast-2"

bar := m.renderStatusBar()
if !strings.Contains(bar, "region:ap-northeast-2") {
Expand All @@ -511,19 +511,19 @@ func TestReachabilityTargetsLoadedBuildsSourceTypeFilter(t *testing.T) {
},
}

updated, _, handled := m.handleEC2VPCMsg(msg)
updated, _, handled := m.reachability.HandleMessage(&m, msg)
if !handled {
t.Fatal("expected message to be handled")
}
model := updated.(Model)
if got := strings.Join(model.reachabilitySourceTypes, ","); got != "EC2 instances,Network interfaces" {
if got := strings.Join(model.reachability.sourceTypes, ","); got != "EC2 instances,Network interfaces" {
t.Fatalf("unexpected source types: %q", got)
}
if len(model.filteredReachabilityTargets) != 1 {
t.Fatalf("expected only EC2 instances to be visible initially, got %d", len(model.filteredReachabilityTargets))
if len(model.reachability.filteredTargets) != 1 {
t.Fatalf("expected only EC2 instances to be visible initially, got %d", len(model.reachability.filteredTargets))
}
if model.filteredReachabilityTargets[0].Type != "EC2 instances" {
t.Fatalf("expected EC2 instances to be prioritized, got %+v", model.filteredReachabilityTargets)
if model.reachability.filteredTargets[0].Type != "EC2 instances" {
t.Fatalf("expected EC2 instances to be prioritized, got %+v", model.reachability.filteredTargets)
}
}

Expand Down Expand Up @@ -2664,7 +2664,7 @@ func TestCWLogStreamsLoadedAppendExtendsExistingList(t *testing.T) {

func TestReachabilityResultLinesUseReadableSections(t *testing.T) {
m := New(testConfig(), "", "dev")
m.reachabilityResult = &awsservice.ReachabilityAnalysisResult{
m.reachability.result = &awsservice.ReachabilityAnalysisResult{
Status: "failed",
NetworkPathFound: false,
Source: awsservice.ReachabilityTarget{Name: "src", ID: "eni-1"},
Expand All @@ -2679,7 +2679,7 @@ func TestReachabilityResultLinesUseReadableSections(t *testing.T) {
},
}

lines := m.reachabilityResultLines()
lines := m.reachability.resultLines(m)
rendered := strings.Join(lines, "\n")
if !strings.Contains(rendered, "Summary") {
t.Fatalf("expected Summary section, got %q", rendered)
Expand All @@ -2694,13 +2694,13 @@ func TestReachabilityResultLinesUseReadableSections(t *testing.T) {

func TestReachabilityLoadingDetailsShowSourceAndDestination(t *testing.T) {
m := New(testConfig(), "", "dev")
m.reachabilityRegion = "ap-northeast-2"
m.reachabilitySource = &awsservice.ReachabilityTarget{Name: "source-eni", ID: "eni-1"}
m.reachabilityDestination = &awsservice.ReachabilityTarget{Name: "dest-eni", ID: "eni-2"}
m.reachabilityProtocolIdx = 0
m.reachabilityPortInput = "443"
m.reachability.region = "ap-northeast-2"
m.reachability.source = &awsservice.ReachabilityTarget{Name: "source-eni", ID: "eni-1"}
m.reachability.destination = &awsservice.ReachabilityTarget{Name: "dest-eni", ID: "eni-2"}
m.reachability.protocolIdx = 0
m.reachability.portInput = "443"

details := m.reachabilityLoadingDetails()
details := m.reachability.loadingDetails(m)
if len(details) < 4 {
t.Fatalf("expected vertical loading details, got %#v", details)
}
Expand All @@ -2727,10 +2727,10 @@ func TestReachabilityLoadingDetailsShowSourceAndDestination(t *testing.T) {
func TestReachabilityLoadingDetailsTruncateLongLabelsForNarrowWidth(t *testing.T) {
m := New(testConfig(), "", "dev")
m.width = 30
m.reachabilitySource = &awsservice.ReachabilityTarget{Name: strings.Repeat("source-", 8), ID: "eni-1"}
m.reachabilityDestination = &awsservice.ReachabilityTarget{Name: strings.Repeat("dest-", 8), ID: "eni-2"}
m.reachability.source = &awsservice.ReachabilityTarget{Name: strings.Repeat("source-", 8), ID: "eni-1"}
m.reachability.destination = &awsservice.ReachabilityTarget{Name: strings.Repeat("dest-", 8), ID: "eni-2"}

details := m.reachabilityLoadingDetails()
details := m.reachability.loadingDetails(m)
if !strings.Contains(details[1], "…") {
t.Fatalf("expected truncated source label, got %#v", details)
}
Expand Down
2 changes: 1 addition & 1 deletion internal/app/feature_submodel.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,5 +10,5 @@ type featureSubmodel interface {
}

func (m *Model) featureSubmodels() []featureSubmodel {
return []featureSubmodel{&m.ec2Browser, &m.cwMetrics, &m.cwLogs, &m.rds, &m.route53, &m.iam, &m.bedrock, &m.secrets, &m.s3, &m.lambda}
return []featureSubmodel{&m.ec2Browser, &m.ecs, &m.vpc, &m.reachability, &m.cwMetrics, &m.cwLogs, &m.rds, &m.route53, &m.iam, &m.bedrock, &m.secrets, &m.s3, &m.lambda}
}
14 changes: 0 additions & 14 deletions internal/app/filter.go
Original file line number Diff line number Diff line change
Expand Up @@ -168,17 +168,9 @@ func (m *Model) applyFilterTarget(target filterTarget) {
case filterInstances:
m.filtered = applyFilter(m.instances, m.filterValue(target))
m.instIdx = 0
case filterSubnetIPs:
m.applyIPFilter()
case filterSecurityGroups:
m.filteredSecurityGroups = applyFilter(m.securityGroups, m.filterValue(target))
m.sgIdx = 0
case filterECSClusters:
m.filteredECSClusters = applyFilter(m.ecsClusters, m.filterValue(target))
m.ecsClusterIdx = 0
case filterECSServices:
m.filteredECSServices = applyFilter(m.ecsServices, m.filterValue(target))
m.ecsServiceIdx = 0
case filterEKSClusters:
m.filteredEKSClusters = applyFilter(m.eksClusters, m.filterValue(target))
m.eksClusterIdx = 0
Expand All @@ -198,12 +190,6 @@ func (m *Model) applyFilterTarget(target filterTarget) {
m.filteredCtxList = applyFilter(m.ctxList, m.filterValue(target))
m.ctxIdx = 0
m.syncContextTable()
case filterVPCs:
m.filteredVPCs = applyFilter(m.vpcs, m.filterValue(target))
m.vpcIdx = 0
case filterSubnets:
m.filteredSubnets = applyFilter(m.subnets, m.filterValue(target))
m.subnetIdx = 0
case filterInspectorChecklistFiles:
m.filteredChecklistFiles = applyFilter(m.inspectorChecklistFiles, m.filterValue(target))
m.inspectorChecklistFileIdx = 0
Expand Down
4 changes: 2 additions & 2 deletions internal/app/help.go
Original file line number Diff line number Diff line change
Expand Up @@ -96,13 +96,13 @@ func (m Model) helpModeShortcuts() []helpShortcut {
}
shortcuts = append(shortcuts, helpShortcut{"esc", "Close filter mode"})
return shortcuts
case m.screen == screenReachabilityRegionList && m.reachabilityRegionFiltering:
case m.screen == screenReachabilityRegionList && m.reachability.regionFiltering:
return []helpShortcut{
{"type", "Update the region filter"},
{"backspace", "Delete the previous character"},
{"enter / esc", "Close region filter mode"},
}
case (m.screen == screenReachabilitySourceList || m.screen == screenReachabilityDestinationList) && m.reachabilityFilterActive:
case (m.screen == screenReachabilitySourceList || m.screen == screenReachabilityDestinationList) && m.reachability.filterActive:
return []helpShortcut{
{"type", "Update the target filter"},
{"backspace", "Delete the previous character"},
Expand Down
Loading
Loading