Skip to content

Commit fd5e2ee

Browse files
committed
Refactor dialog close action handling and ensure close option is last in dialog options
1 parent 98ee226 commit fd5e2ee

7 files changed

Lines changed: 129 additions & 1 deletion

internal/ui/dialog/delete_file_dialog.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -86,6 +86,7 @@ func (d *DeleteFileDialog) selectAction(option *DialogOption) {
8686
case DeleteFileDialogDeleteFileActionId:
8787
d.DeleteFile()
8888
case DialogCloseActionId:
89+
d.Close()
8990
default:
9091
d.Close()
9192
}

internal/ui/dialog/delete_snapshot_dialog.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -84,6 +84,7 @@ func (d *DeleteSnapshotDialog) selectAction(option *DialogOption) {
8484
case DeleteSnapshotDialogDeleteSnapshotActionId:
8585
d.DeleteSnapshot()
8686
case DialogCloseActionId:
87+
d.Close()
8788
default:
8889
d.Close()
8990
}
Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
package dialog
2+
3+
import (
4+
"testing"
5+
"time"
6+
"zfs-file-history/internal/data"
7+
8+
"github.com/stretchr/testify/assert"
9+
)
10+
11+
func TestSnapshotActionDialog_SelectCloseOption_EmitsCloseAction(t *testing.T) {
12+
d := &SnapshotActionDialog{actionChannel: make(chan DialogActionId, 1)}
13+
14+
d.selectAction(&DialogOption{Id: DialogCloseActionId, Name: "Close"})
15+
16+
assertDialogActionEmitted(t, d.actionChannel, DialogCloseActionId)
17+
}
18+
19+
func TestDeleteFileDialog_SelectCancelOption_EmitsCloseAction(t *testing.T) {
20+
d := &DeleteFileDialog{actionChannel: make(chan DialogActionId, 1)}
21+
22+
d.selectAction(&DialogOption{Id: DialogCloseActionId, Name: "Cancel"})
23+
24+
assertDialogActionEmitted(t, d.actionChannel, DialogCloseActionId)
25+
}
26+
27+
func TestDeleteSnapshotDialog_SelectCancelOption_EmitsCloseAction(t *testing.T) {
28+
d := &DeleteSnapshotDialog{actionChannel: make(chan DialogActionId, 1)}
29+
30+
d.selectAction(&DialogOption{Id: DialogCloseActionId, Name: "Cancel"})
31+
32+
assertDialogActionEmitted(t, d.actionChannel, DialogCloseActionId)
33+
}
34+
35+
func TestMultiSnapshotActionDialog_SelectCloseOption_EmitsCloseAction(t *testing.T) {
36+
d := &MultiSnapshotActionDialog{actionChannel: make(chan DialogActionId, 1)}
37+
38+
d.selectAction(&DialogOption{Id: DialogCloseActionId, Name: "Close"})
39+
40+
assertDialogActionEmitted(t, d.actionChannel, DialogCloseActionId)
41+
}
42+
43+
func TestSnapshotActionDialog_SelectCloseOption_DoesNotEmitOtherAction(t *testing.T) {
44+
d := &SnapshotActionDialog{
45+
actionChannel: make(chan DialogActionId, 2),
46+
snapshot: &data.SnapshotBrowserEntry{},
47+
}
48+
49+
d.selectAction(&DialogOption{Id: DialogCloseActionId, Name: "Close"})
50+
51+
assertDialogActionEmitted(t, d.actionChannel, DialogCloseActionId)
52+
assertNoMoreDialogActions(t, d.actionChannel)
53+
}
54+
55+
func assertDialogActionEmitted(t *testing.T, ch <-chan DialogActionId, expected DialogActionId) {
56+
t.Helper()
57+
select {
58+
case action := <-ch:
59+
assert.Equal(t, expected, action)
60+
case <-time.After(100 * time.Millisecond):
61+
t.Fatalf("expected action %v to be emitted", expected)
62+
}
63+
}
64+
65+
func assertNoMoreDialogActions(t *testing.T, ch <-chan DialogActionId) {
66+
t.Helper()
67+
select {
68+
case action := <-ch:
69+
t.Fatalf("did not expect extra dialog action %v", action)
70+
case <-time.After(30 * time.Millisecond):
71+
// expected no more actions
72+
}
73+
}

internal/ui/dialog/file_action_dialog.go

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -103,7 +103,21 @@ func buildFileDialogOptions(file *data.FileBrowserEntry, diffBinAvailable bool)
103103
Name: "Create Snapshot",
104104
})
105105

106-
return dialogOptions
106+
return ensureDialogCloseIsLast(dialogOptions)
107+
}
108+
109+
func ensureDialogCloseIsLast(options []*DialogOption) []*DialogOption {
110+
closeIndex := slices.IndexFunc(options, func(option *DialogOption) bool {
111+
return option != nil && option.Id == DialogCloseActionId
112+
})
113+
if closeIndex < 0 || closeIndex == len(options)-1 {
114+
return options
115+
}
116+
117+
closeOption := options[closeIndex]
118+
result := slices.Delete(options, closeIndex, closeIndex+1)
119+
result = append(result, closeOption)
120+
return result
107121
}
108122

109123
func DiffBinExists() bool {
@@ -147,6 +161,7 @@ func (d *FileActionDialog) selectAction(option *DialogOption) {
147161
case FileDialogCreateSnapshotDialogActionId:
148162
d.CreateSnapshot()
149163
case DialogCloseActionId:
164+
d.Close()
150165
default:
151166
d.Close()
152167
}

internal/ui/dialog/file_action_dialog_test.go

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ package dialog
22

33
import (
44
"testing"
5+
"time"
56
"zfs-file-history/internal/data"
67
"zfs-file-history/internal/data/diff_state"
78

@@ -100,10 +101,45 @@ func TestBuildFileDialogOptions_OnlyRealFile(t *testing.T) {
100101
)
101102
}
102103

104+
func TestBuildFileDialogOptions_DeletedFile_AlwaysHasCloseLast(t *testing.T) {
105+
entry := &data.FileBrowserEntry{
106+
Name: "deleted-in-live.txt",
107+
Type: data.File,
108+
SnapshotFiles: []*data.SnapshotFile{
109+
{},
110+
},
111+
DiffState: diff_state.Deleted,
112+
}
113+
114+
options := buildFileDialogOptions(entry, false)
115+
116+
assert.Equal(t,
117+
[]DialogActionId{
118+
FileDialogCreateSnapshotDialogActionId,
119+
FileDialogRestoreFileActionId,
120+
DialogCloseActionId,
121+
},
122+
optionIds(options),
123+
)
124+
}
125+
103126
func optionIds(options []*DialogOption) []DialogActionId {
104127
result := make([]DialogActionId, 0, len(options))
105128
for _, option := range options {
106129
result = append(result, option.Id)
107130
}
108131
return result
109132
}
133+
134+
func TestFileActionDialog_SelectCloseOption_EmitsCloseAction(t *testing.T) {
135+
d := &FileActionDialog{actionChannel: make(chan DialogActionId, 1)}
136+
137+
d.selectAction(&DialogOption{Id: DialogCloseActionId, Name: "Close"})
138+
139+
select {
140+
case action := <-d.actionChannel:
141+
assert.Equal(t, DialogCloseActionId, action)
142+
case <-time.After(100 * time.Millisecond):
143+
t.Fatal("expected close action to be emitted")
144+
}
145+
}

internal/ui/dialog/snapshot_action_dialog.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -96,6 +96,7 @@ func (d *SnapshotActionDialog) selectAction(option *DialogOption) {
9696
case SnapshotDialogDestroySnapshotRecursivelyActionId:
9797
d.DestroySnapshotRecursively()
9898
case DialogCloseActionId:
99+
d.Close()
99100
default:
100101
d.Close()
101102
}

internal/ui/dialog/snapshot_multi_action_dialog.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -101,6 +101,7 @@ func (d *MultiSnapshotActionDialog) selectAction(option *DialogOption) {
101101
case MultiSnapshotDialogDestroySnapshotRecursivelyActionId:
102102
d.DestroyAllSnapshotsRecursively()
103103
case DialogCloseActionId:
104+
d.Close()
104105
default:
105106
d.Close()
106107
}

0 commit comments

Comments
 (0)