Skip to content

Commit 7d292b2

Browse files
committed
refactor: extract network browser submodels
1 parent f810949 commit 7d292b2

9 files changed

Lines changed: 540 additions & 456 deletions

File tree

internal/app/app.go

Lines changed: 16 additions & 99 deletions
Original file line numberDiff line numberDiff line change
@@ -129,43 +129,6 @@ type Model struct {
129129
// SSM session state
130130
selectedInstance *awsservice.EC2Instance
131131

132-
// VPC browser state
133-
vpcs []awsservice.VPC
134-
filteredVPCs []awsservice.VPC
135-
vpcIdx int
136-
subnets []awsservice.Subnet
137-
filteredSubnets []awsservice.Subnet
138-
subnetIdx int
139-
selectedVPC *awsservice.VPC
140-
selectedSubnet *awsservice.Subnet
141-
availableIPs []string
142-
filteredIPs []string
143-
ipScrollOffset int
144-
ipFilter string
145-
ipFilterActive bool
146-
reachabilityRegions []string
147-
filteredReachabilityRegions []string
148-
reachabilityRegion string
149-
reachabilityRegionIdx int
150-
reachabilityRegionFilter string
151-
reachabilityRegionFiltering bool
152-
reachabilityTargets []awsservice.ReachabilityTarget
153-
filteredReachabilityTargets []awsservice.ReachabilityTarget
154-
reachabilitySourceTypes []string
155-
reachabilitySourceTypeIdx int
156-
reachabilityDestTypes []string
157-
reachabilityDestTypeIdx int
158-
reachabilityIdx int
159-
reachabilityFilter string
160-
reachabilityFilterActive bool
161-
reachabilitySource *awsservice.ReachabilityTarget
162-
reachabilityDestination *awsservice.ReachabilityTarget
163-
reachabilityDestinationIP string
164-
reachabilityProtocolIdx int
165-
reachabilityPortInput string
166-
reachabilityConfigField int
167-
reachabilityResult *awsservice.ReachabilityAnalysisResult
168-
reachabilityScrollOffset int
169132
// Security Group browser state
170133
securityGroups []awsservice.SecurityGroup
171134
filteredSecurityGroups []awsservice.SecurityGroup
@@ -230,16 +193,18 @@ type Model struct {
230193
ecrCopyMsg string
231194

232195
// Feature submodels
233-
ec2Browser ec2InstanceBrowserModel
234-
cwMetrics cloudWatchMetricsModel
235-
cwLogs cloudWatchLogsModel
236-
rds rdsModel
237-
route53 route53Model
238-
iam iamModel
239-
bedrock bedrockModel
240-
secrets secretsModel
241-
s3 s3Model
242-
lambda lambdaModel
196+
ec2Browser ec2InstanceBrowserModel
197+
vpc vpcModel
198+
reachability reachabilityModel
199+
cwMetrics cloudWatchMetricsModel
200+
cwLogs cloudWatchLogsModel
201+
rds rdsModel
202+
route53 route53Model
203+
iam iamModel
204+
bedrock bedrockModel
205+
secrets secretsModel
206+
s3 s3Model
207+
lambda lambdaModel
243208

244209
// Inspector browser state
245210
inspectorWorkflows []inspector.Workflow
@@ -339,6 +304,8 @@ func New(cfg *config.Config, configPath string, version string, checklistPath ..
339304
contextTable: newContextTable(),
340305
}
341306
model.ec2Browser = newEC2InstanceBrowserModel()
307+
model.vpc = newVPCModel()
308+
model.reachability = newReachabilityModel()
342309
model.cwMetrics = newCloudWatchMetricsModel()
343310
model.cwLogs = newCloudWatchLogsModel()
344311
model.rds = newRDSModel()
@@ -515,22 +482,6 @@ func (m Model) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
515482
return m.updateFeatureList(msg)
516483
case screenInstanceList:
517484
return m.updateInstanceList(msg)
518-
case screenVPCList:
519-
return m.updateVPCList(msg)
520-
case screenSubnetList:
521-
return m.updateSubnetList(msg)
522-
case screenSubnetDetail:
523-
return m.updateSubnetDetail(msg)
524-
case screenReachabilityRegionList:
525-
return m.updateReachabilityRegionList(msg)
526-
case screenReachabilitySourceList:
527-
return m.updateReachabilitySourceList(msg)
528-
case screenReachabilityDestinationList:
529-
return m.updateReachabilityDestinationList(msg)
530-
case screenReachabilityConfig:
531-
return m.updateReachabilityConfig(msg)
532-
case screenReachabilityResult:
533-
return m.updateReachabilityResult(msg)
534485
case screenInspectorHome:
535486
return m.updateInspectorHome(msg)
536487
case screenInspectorWorkflowPlaceholder:
@@ -660,27 +611,9 @@ func (m Model) updateFeatureList(msg tea.KeyMsg) (tea.Model, tea.Cmd) {
660611
case domain.FeatureEC2InstanceBrowser:
661612
return m.ec2Browser.Start(&m)
662613
case domain.FeatureVPCBrowser:
663-
return m.startLoading(m.loadVPCs())
614+
return m.vpc.Start(&m)
664615
case domain.FeatureReachabilityAnalyzer:
665-
m.reachabilityRegions = availableReachabilityRegions(m.cfg.Region)
666-
m.filteredReachabilityRegions = m.reachabilityRegions
667-
m.reachabilityRegion = m.cfg.Region
668-
m.reachabilityRegionIdx = indexOfString(m.reachabilityRegions, m.reachabilityRegion)
669-
if m.reachabilityRegionIdx < 0 {
670-
m.reachabilityRegionIdx = 0
671-
}
672-
m.reachabilityRegionFilter = ""
673-
m.reachabilityRegionFiltering = false
674-
m.reachabilityTargets = nil
675-
m.filteredReachabilityTargets = nil
676-
m.reachabilitySource = nil
677-
m.reachabilityDestination = nil
678-
m.reachabilityDestinationIP = ""
679-
m.reachabilityResult = nil
680-
m.reachabilityScrollOffset = 0
681-
m.awsRepo = nil
682-
m.screen = screenReachabilityRegionList
683-
return m, nil
616+
return m.reachability.Start(&m)
684617
case domain.FeatureRDSBrowser:
685618
return m.rds.Start(&m)
686619
case domain.FeatureRoute53Browser:
@@ -751,22 +684,6 @@ func (m Model) View() string {
751684
v = m.viewFeatureList()
752685
case screenInstanceList:
753686
v = m.viewInstanceList()
754-
case screenVPCList:
755-
v = m.viewVPCList()
756-
case screenSubnetList:
757-
v = m.viewSubnetList()
758-
case screenSubnetDetail:
759-
v = m.viewSubnetDetail()
760-
case screenReachabilityRegionList:
761-
v = m.viewReachabilityRegionList()
762-
case screenReachabilitySourceList:
763-
v = m.viewReachabilitySourceList()
764-
case screenReachabilityDestinationList:
765-
v = m.viewReachabilityDestinationList()
766-
case screenReachabilityConfig:
767-
v = m.viewReachabilityConfig()
768-
case screenReachabilityResult:
769-
v = m.viewReachabilityResult()
770687
case screenInspectorHome:
771688
v = m.viewInspectorHome()
772689
case screenInspectorWorkflowPlaceholder:

internal/app/app_test.go

Lines changed: 20 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -486,15 +486,15 @@ func TestReachabilityFeatureOpensRegionSelection(t *testing.T) {
486486
if model.screen != screenReachabilityRegionList {
487487
t.Fatalf("expected region selection screen, got %v", model.screen)
488488
}
489-
if model.reachabilityRegion != "us-east-1" {
490-
t.Fatalf("expected default reachability region us-east-1, got %q", model.reachabilityRegion)
489+
if model.reachability.region != "us-east-1" {
490+
t.Fatalf("expected default reachability region us-east-1, got %q", model.reachability.region)
491491
}
492492
}
493493

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

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

514-
updated, _, handled := m.handleEC2VPCMsg(msg)
514+
updated, _, handled := m.reachability.HandleMessage(&m, msg)
515515
if !handled {
516516
t.Fatal("expected message to be handled")
517517
}
518518
model := updated.(Model)
519-
if got := strings.Join(model.reachabilitySourceTypes, ","); got != "EC2 instances,Network interfaces" {
519+
if got := strings.Join(model.reachability.sourceTypes, ","); got != "EC2 instances,Network interfaces" {
520520
t.Fatalf("unexpected source types: %q", got)
521521
}
522-
if len(model.filteredReachabilityTargets) != 1 {
523-
t.Fatalf("expected only EC2 instances to be visible initially, got %d", len(model.filteredReachabilityTargets))
522+
if len(model.reachability.filteredTargets) != 1 {
523+
t.Fatalf("expected only EC2 instances to be visible initially, got %d", len(model.reachability.filteredTargets))
524524
}
525-
if model.filteredReachabilityTargets[0].Type != "EC2 instances" {
526-
t.Fatalf("expected EC2 instances to be prioritized, got %+v", model.filteredReachabilityTargets)
525+
if model.reachability.filteredTargets[0].Type != "EC2 instances" {
526+
t.Fatalf("expected EC2 instances to be prioritized, got %+v", model.reachability.filteredTargets)
527527
}
528528
}
529529

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

26652665
func TestReachabilityResultLinesUseReadableSections(t *testing.T) {
26662666
m := New(testConfig(), "", "dev")
2667-
m.reachabilityResult = &awsservice.ReachabilityAnalysisResult{
2667+
m.reachability.result = &awsservice.ReachabilityAnalysisResult{
26682668
Status: "failed",
26692669
NetworkPathFound: false,
26702670
Source: awsservice.ReachabilityTarget{Name: "src", ID: "eni-1"},
@@ -2679,7 +2679,7 @@ func TestReachabilityResultLinesUseReadableSections(t *testing.T) {
26792679
},
26802680
}
26812681

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

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

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

2733-
details := m.reachabilityLoadingDetails()
2733+
details := m.reachability.loadingDetails(m)
27342734
if !strings.Contains(details[1], "…") {
27352735
t.Fatalf("expected truncated source label, got %#v", details)
27362736
}

internal/app/feature_submodel.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,5 +10,5 @@ type featureSubmodel interface {
1010
}
1111

1212
func (m *Model) featureSubmodels() []featureSubmodel {
13-
return []featureSubmodel{&m.ec2Browser, &m.cwMetrics, &m.cwLogs, &m.rds, &m.route53, &m.iam, &m.bedrock, &m.secrets, &m.s3, &m.lambda}
13+
return []featureSubmodel{&m.ec2Browser, &m.vpc, &m.reachability, &m.cwMetrics, &m.cwLogs, &m.rds, &m.route53, &m.iam, &m.bedrock, &m.secrets, &m.s3, &m.lambda}
1414
}

internal/app/filter.go

Lines changed: 0 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -168,8 +168,6 @@ func (m *Model) applyFilterTarget(target filterTarget) {
168168
case filterInstances:
169169
m.filtered = applyFilter(m.instances, m.filterValue(target))
170170
m.instIdx = 0
171-
case filterSubnetIPs:
172-
m.applyIPFilter()
173171
case filterSecurityGroups:
174172
m.filteredSecurityGroups = applyFilter(m.securityGroups, m.filterValue(target))
175173
m.sgIdx = 0
@@ -198,12 +196,6 @@ func (m *Model) applyFilterTarget(target filterTarget) {
198196
m.filteredCtxList = applyFilter(m.ctxList, m.filterValue(target))
199197
m.ctxIdx = 0
200198
m.syncContextTable()
201-
case filterVPCs:
202-
m.filteredVPCs = applyFilter(m.vpcs, m.filterValue(target))
203-
m.vpcIdx = 0
204-
case filterSubnets:
205-
m.filteredSubnets = applyFilter(m.subnets, m.filterValue(target))
206-
m.subnetIdx = 0
207199
case filterInspectorChecklistFiles:
208200
m.filteredChecklistFiles = applyFilter(m.inspectorChecklistFiles, m.filterValue(target))
209201
m.inspectorChecklistFileIdx = 0

internal/app/help.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -96,13 +96,13 @@ func (m Model) helpModeShortcuts() []helpShortcut {
9696
}
9797
shortcuts = append(shortcuts, helpShortcut{"esc", "Close filter mode"})
9898
return shortcuts
99-
case m.screen == screenReachabilityRegionList && m.reachabilityRegionFiltering:
99+
case m.screen == screenReachabilityRegionList && m.reachability.regionFiltering:
100100
return []helpShortcut{
101101
{"type", "Update the region filter"},
102102
{"backspace", "Delete the previous character"},
103103
{"enter / esc", "Close region filter mode"},
104104
}
105-
case (m.screen == screenReachabilitySourceList || m.screen == screenReachabilityDestinationList) && m.reachabilityFilterActive:
105+
case (m.screen == screenReachabilitySourceList || m.screen == screenReachabilityDestinationList) && m.reachability.filterActive:
106106
return []helpShortcut{
107107
{"type", "Update the target filter"},
108108
{"backspace", "Delete the previous character"},

internal/app/screen_ec2.go

Lines changed: 0 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -19,53 +19,6 @@ func (m Model) handleEC2VPCMsg(msg tea.Msg) (tea.Model, tea.Cmd, bool) {
1919
m.screen = screenInstanceList
2020
return m, nil, true
2121

22-
case vpcsLoadedMsg:
23-
m.vpcs = msg.vpcs
24-
m.resetFilter(filterVPCs)
25-
m.vpcIdx = 0
26-
m.screen = screenVPCList
27-
return m, nil, true
28-
29-
case subnetsLoadedMsg:
30-
m.subnets = msg.subnets
31-
m.resetFilter(filterSubnets)
32-
m.subnetIdx = 0
33-
m.screen = screenSubnetList
34-
return m, nil, true
35-
36-
case availableIPsLoadedMsg:
37-
m.availableIPs = msg.ips
38-
m.resetFilter(filterSubnetIPs)
39-
m.screen = screenSubnetDetail
40-
return m, nil, true
41-
42-
case reachabilityTargetsLoadedMsg:
43-
m.reachabilityTargets = msg.targets
44-
m.reachabilitySourceTypes = buildReachabilityTargetTypes(msg.targets, false)
45-
m.reachabilitySourceTypeIdx = 0
46-
m.reachabilityDestTypes = nil
47-
m.reachabilityDestTypeIdx = 0
48-
m.filteredReachabilityTargets = applyReachabilityTargetFilter(msg.targets, m.selectedReachabilitySourceType(), "")
49-
m.reachabilityIdx = 0
50-
m.reachabilityFilter = ""
51-
m.reachabilityFilterActive = false
52-
m.reachabilitySource = nil
53-
m.reachabilityDestination = nil
54-
m.reachabilityDestinationIP = ""
55-
m.reachabilityProtocolIdx = 0
56-
m.reachabilityPortInput = "443"
57-
m.reachabilityConfigField = 0
58-
m.reachabilityResult = nil
59-
m.reachabilityScrollOffset = 0
60-
m.screen = screenReachabilitySourceList
61-
return m, nil, true
62-
63-
case reachabilityAnalysisLoadedMsg:
64-
m.reachabilityResult = msg.result
65-
m.reachabilityScrollOffset = 0
66-
m.screen = screenReachabilityResult
67-
return m, nil, true
68-
6922
case ssmSessionDoneMsg:
7023
if msg.err != nil {
7124
m.errMsg = msg.err.Error()

0 commit comments

Comments
 (0)