Merge contextual Target actions with Profile workflows
This commit is contained in:
+24
-19
@@ -43,13 +43,13 @@ func (m *targetModule) StartOperation(intent app.Intent) app.OperationStream {
|
||||
|
||||
func TestTargetPanelShowsOnlyAvailableTargetsAndAppliesAsynchronously(t *testing.T) {
|
||||
module := &targetModule{snapshot: app.Snapshot{ActiveProfile: "office", Targets: []app.TargetSnapshot{
|
||||
{ID: "shell", Description: target.Description{Name: "Shell", Summary: "Exports for Bash/Zsh"}, Available: true, State: target.External, Evidence: "existing proxy"},
|
||||
{ID: "shell", Description: target.Description{Name: "Shell", Summary: "Exports for Bash/Zsh"}, Available: true, State: target.External, Evidence: "existing proxy", PrimaryAction: app.TargetAction{Kind: app.ApplyProfileTargetAction, Available: true}},
|
||||
{ID: "apt", Description: target.Description{Name: "APT"}, Available: false},
|
||||
}}}
|
||||
module.result = app.Result{Snapshot: app.Snapshot{ActiveProfile: "office", Targets: []app.TargetSnapshot{{ID: "shell", Description: target.Description{Name: "Shell", Summary: "Exports for Bash/Zsh"}, Available: true, State: target.Enabled, Evidence: "matches"}}}, Notice: "Shell Target is now Enabled"}
|
||||
module.result = app.Result{Snapshot: app.Snapshot{ActiveProfile: "office", Targets: []app.TargetSnapshot{{ID: "shell", Description: target.Description{Name: "Shell", Summary: "Exports for Bash/Zsh"}, Available: true, State: target.Enabled, Evidence: "matches", PrimaryAction: app.TargetAction{Kind: app.DisableTargetAction, Available: true}}}}, Notice: "Shell Target is now Enabled"}
|
||||
model := NewModel(module)
|
||||
view := model.View()
|
||||
if !strings.Contains(view, "Shell") || strings.Contains(view, "APT") || !strings.Contains(view, "Exports for Bash/Zsh") {
|
||||
if !strings.Contains(view, "Shell") || strings.Contains(view, "APT") || !strings.Contains(view, "Action: Apply Profile") {
|
||||
t.Fatalf("Target panel:\n%s", view)
|
||||
}
|
||||
|
||||
@@ -61,13 +61,13 @@ func TestTargetPanelShowsOnlyAvailableTargetsAndAppliesAsynchronously(t *testing
|
||||
message := command()
|
||||
updated, _ = model.Update(message)
|
||||
model = updated.(Model)
|
||||
if len(module.intents) != 1 || module.intents[0].Kind != app.SetTargetDesired || !module.intents[0].Enabled || !strings.Contains(model.View(), "Enabled") {
|
||||
if len(module.intents) != 1 || module.intents[0].Kind != app.ApplyProfileToTarget || !strings.Contains(model.View(), "Enabled") {
|
||||
t.Fatalf("completed toggle = %#v\n%s", module.intents, model.View())
|
||||
}
|
||||
}
|
||||
|
||||
func TestTargetRestartConfirmationCancelsWithoutConfirmedMutation(t *testing.T) {
|
||||
initial := app.Snapshot{ActiveProfile: "office", Targets: []app.TargetSnapshot{{ID: "docker-daemon", Description: target.Description{Name: "Docker daemon"}, Available: true, State: target.Disabled}}}
|
||||
initial := app.Snapshot{ActiveProfile: "office", Targets: []app.TargetSnapshot{{ID: "docker-daemon", Description: target.Description{Name: "Docker daemon"}, Available: true, State: target.Disabled, PrimaryAction: app.TargetAction{Kind: app.EnableTargetAction, Available: true}}}}
|
||||
module := &targetModule{snapshot: initial, result: app.Result{Snapshot: initial, ConfirmationRequest: &app.Confirmation{Title: "Confirm Docker restart", Summary: "Docker will restart immediately and may disrupt running work.", ConfirmLabel: "Continue", CancelLabel: "Cancel"}}}
|
||||
model := NewModel(module)
|
||||
updated, command := model.Update(tea.KeyMsg{Type: tea.KeySpace})
|
||||
@@ -88,7 +88,7 @@ func TestTargetRestartConfirmationCancelsWithoutConfirmedMutation(t *testing.T)
|
||||
updated, _ = model.Update(command())
|
||||
model = updated.(Model)
|
||||
module.result = app.Result{
|
||||
Snapshot: app.Snapshot{ActiveProfile: "office", Targets: []app.TargetSnapshot{{ID: "docker-daemon", Description: target.Description{Name: "Docker daemon"}, Available: true, State: target.Enabled}}},
|
||||
Snapshot: app.Snapshot{ActiveProfile: "office", Targets: []app.TargetSnapshot{{ID: "docker-daemon", Description: target.Description{Name: "Docker daemon"}, Available: true, State: target.Enabled, PrimaryAction: app.TargetAction{Kind: app.DisableTargetAction, Available: true}}}},
|
||||
Notice: "Docker daemon Target is now Enabled",
|
||||
}
|
||||
updated, command = model.Update(tea.KeyMsg{Type: tea.KeyRunes, Runes: []rune{'y'}})
|
||||
@@ -104,12 +104,12 @@ func TestTargetRestartConfirmationCancelsWithoutConfirmedMutation(t *testing.T)
|
||||
|
||||
func TestHelpListsEveryTargetAndMainListsOnlyAvailableTargets(t *testing.T) {
|
||||
module := &targetModule{snapshot: app.Snapshot{Targets: []app.TargetSnapshot{
|
||||
{ID: "shell", Description: target.Description{Name: "Shell", Summary: "summary", Details: "affects future Shell commands; does not affect daemons; owns a generated fragment; user permission; reload side effect"}, Available: true, State: target.Disabled, Evidence: "integration installed"},
|
||||
{ID: "shell", Description: target.Description{Name: "Shell", Summary: "summary", Details: "affects future Shell commands; does not affect daemons; owns a generated fragment; user permission; reload side effect"}, Available: true, State: target.Disabled, Evidence: "integration installed", PrimaryAction: app.TargetAction{Kind: app.EnableTargetAction, Available: false, DisabledReason: "This action is unavailable because there is no Active Profile; open Profile management first"}},
|
||||
{ID: "apt", Description: target.Description{Name: "APT", Summary: "persistent package proxy", Details: "owns an overlay and requires system write permission"}, Available: false, AvailabilityEvidence: "Debian APT tool apt-config was not detected"},
|
||||
}}}
|
||||
model := NewModel(module)
|
||||
view := model.View()
|
||||
if strings.Contains(view, "APT") || !strings.Contains(view, "summary") || !strings.Contains(view, "integration installed") {
|
||||
if strings.Contains(view, "APT") || !strings.Contains(view, "Action: Enable") || !strings.Contains(view, "integration installed") {
|
||||
t.Fatalf("main Target panel:\n%s", view)
|
||||
}
|
||||
model = updateKey(model, "?")
|
||||
@@ -344,22 +344,27 @@ func TestTargetPanelRendersEveryTargetState(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestDriftedTargetWithoutActiveProfileTogglesTowardDisabled(t *testing.T) {
|
||||
initial := app.Snapshot{Targets: []app.TargetSnapshot{{ID: "shell", Description: target.Description{Name: "Shell"}, Available: true, State: target.Drifted}}}
|
||||
module := &targetModule{snapshot: initial, result: app.Result{Snapshot: app.Snapshot{Targets: []app.TargetSnapshot{{ID: "shell", Description: target.Description{Name: "Shell"}, Available: true, State: target.Disabled}}}}}
|
||||
func TestDriftedTargetWithoutActiveProfileRequiresExplicitResolutionDirection(t *testing.T) {
|
||||
initial := app.Snapshot{Targets: []app.TargetSnapshot{{
|
||||
ID: "shell", Description: target.Description{Name: "Shell"}, Available: true, State: target.Drifted,
|
||||
PrimaryAction: app.TargetAction{Kind: app.ResolveDriftTargetAction, Available: true},
|
||||
DriftResolutionActions: []app.TargetAction{{Kind: app.ReapplyActiveProfileAction}, {Kind: app.RestoreOriginalAction, Available: true}},
|
||||
}}}
|
||||
initial.Targets[0].DriftResolutionActions[0].DisabledReason = "Reapply Active Profile is unavailable because there is no Active Profile"
|
||||
module := &targetModule{snapshot: initial}
|
||||
model := NewModel(module)
|
||||
_, command := model.Update(tea.KeyMsg{Type: tea.KeySpace})
|
||||
if command == nil {
|
||||
t.Fatal("Drifted Target did not start disable")
|
||||
}
|
||||
_ = command()
|
||||
if len(module.intents) != 1 || module.intents[0].Enabled {
|
||||
t.Fatalf("Drifted Target intent = %#v", module.intents)
|
||||
updated, command := model.Update(tea.KeyMsg{Type: tea.KeySpace})
|
||||
model = updated.(Model)
|
||||
if command != nil || len(module.intents) != 0 || !strings.Contains(model.View(), "Drift Resolution") || !strings.Contains(model.View(), "Reapply Active Profile is unavailable") {
|
||||
t.Fatalf("Drifted Target chose a direction implicitly: intents=%#v\n%s", module.intents, model.View())
|
||||
}
|
||||
}
|
||||
|
||||
func TestTargetFailurePreservesTruthfulStateAndRendersRedactedError(t *testing.T) {
|
||||
initial := app.Snapshot{ActiveProfile: "office", Targets: []app.TargetSnapshot{{ID: "shell", Description: target.Description{Name: "Shell"}, Available: true, State: target.Enabled}}}
|
||||
initial := app.Snapshot{ActiveProfile: "office", Targets: []app.TargetSnapshot{{
|
||||
ID: "shell", Description: target.Description{Name: "Shell"}, Available: true, State: target.Enabled,
|
||||
PrimaryAction: app.TargetAction{Kind: app.DisableTargetAction, Available: true},
|
||||
}}}
|
||||
module := &targetModule{snapshot: initial, result: app.Result{Snapshot: initial, Err: errors.New("permission denied for alice:REDACTED@proxy")}}
|
||||
model := NewModel(module)
|
||||
updated, command := model.Update(tea.KeyMsg{Type: tea.KeySpace})
|
||||
|
||||
Reference in New Issue
Block a user