-
Notifications
You must be signed in to change notification settings - Fork 0
/
archive.go
142 lines (113 loc) · 2.62 KB
/
archive.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
package project
import (
"fmt"
"github.com/philipf/gt/internal/toggl"
"github.com/spf13/cobra"
tea "github.com/charmbracelet/bubbletea"
)
var filter toggl.GetProjectsOpts
var archiveCmd = &cobra.Command{
Use: "archive",
Short: "Archive projects",
Long: `Archives projects using the Toggl API
Example:
gt toggl project archive
`,
Run: func(cmd *cobra.Command, _ []string) {
clientId, err := cmd.Flags().GetInt64("clientId")
cobra.CheckErr(err)
name, err := cmd.Flags().GetString("name")
cobra.CheckErr(err)
filter = toggl.GetProjectsOpts{
ClientID: clientId,
Name: name,
}
items, err := projectService.Get(&filter)
cobra.CheckErr(err)
m := model{
projects: items,
selected: make(map[int]struct{}),
}
p := tea.NewProgram(m)
_, err = p.Run()
cobra.CheckErr(err)
// print all the selected projects
for i := range m.selected {
err := projectService.Archive(m.projects[i].ID)
cobra.CheckErr(err)
fmt.Println("Archived project", m.projects[i].Name)
}
},
}
func fetchProjects() tea.Msg {
return func() tea.Msg {
projects, err := projectService.Get(&filter)
if err != nil {
return errMsg{err}
}
return projects
}
}
type errMsg struct{ err error }
// For messages that contain errors it's often handy to also implement the
// error interface on the message.
func (e errMsg) Error() string { return e.err.Error() }
func init() {
projectCmd.AddCommand(archiveCmd)
// filter
archiveCmd.Flags().Int64P("clientId", "c", 0, "Filter by client ID")
archiveCmd.Flags().StringP("name", "n", "", "Filter by project name")
}
type model struct {
projects toggl.TogglProjects
cursor int
selected map[int]struct{}
}
func (m model) Init() tea.Cmd {
return fetchProjects
}
func (m model) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
switch msg := msg.(type) {
case tea.KeyMsg:
switch msg.String() {
case "ctrl+c", "q":
return m, tea.Quit
case "w":
return m, tea.Quit
case "up", "k":
if m.cursor > 0 {
m.cursor--
} else {
m.cursor = len(m.projects) - 1
}
case "down", "j":
if m.cursor < len(m.projects)-1 {
m.cursor++
} else {
m.cursor = 0
}
case "enter", " ":
if _, ok := m.selected[m.cursor]; ok {
delete(m.selected, m.cursor)
} else {
m.selected[m.cursor] = struct{}{}
}
}
}
return m, nil
}
func (m model) View() string {
s := "Select projects to archive [Q]uit/[W]rite:\n\n"
for i, p := range m.projects {
checked := " "
if _, ok := m.selected[i]; ok {
checked = "x"
}
cursor := " "
if m.cursor == i {
cursor = ">"
}
s += fmt.Sprintf("%s [%s] %s\n", cursor, checked, p.Name)
}
return s
}