Skip to content

Commit

Permalink
feat: add ability to save manual entries
Browse files Browse the repository at this point in the history
  • Loading branch information
dhth committed Mar 13, 2024
1 parent 27b49fd commit af39d15
Show file tree
Hide file tree
Showing 9 changed files with 273 additions and 41 deletions.
22 changes: 22 additions & 0 deletions ui/cmds.go
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,28 @@ func insertEntry(db *sql.DB, issue_key string) tea.Cmd {
}
}

func insertManualEntry(db *sql.DB, issueKey string, beginTS time.Time, endTS time.Time, comment string) tea.Cmd {
return func() tea.Msg {

stmt, err := db.Prepare(`
INSERT INTO issue_log (issue_key, begin_ts, end_ts, comment, active, synced)
VALUES (?, ?, ?, ?, ?, ?);
`)

if err != nil {
return ManualEntryInserted{issueKey, err}
}
defer stmt.Close()

_, err = stmt.Exec(issueKey, beginTS, endTS, comment, false, false)
if err != nil {
return ManualEntryInserted{issueKey, err}
}

return ManualEntryInserted{issueKey, nil}
}
}

func updateEntry(db *sql.DB, issue_key string) tea.Cmd {
return func() tea.Msg {

Expand Down
6 changes: 6 additions & 0 deletions ui/help.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,12 @@ General List Controls
l<Right> Go to next page
/ Start filtering
Issue List View
s Toggle recording time on the currently selected issue,
will open up a form to record a comment on the second
"s" keypress
<ctrl+s> Add manual worklog entry
Worklog List View
<ctrl+d> Delete worklog entry
s Sync all visible entries to JIRA
Expand Down
25 changes: 20 additions & 5 deletions ui/initial.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import (

jira "github.com/andygrunwald/go-jira/v2/onpremise"
"github.com/charmbracelet/bubbles/list"
"github.com/charmbracelet/bubbles/textarea"
"github.com/charmbracelet/bubbles/textinput"
)

func InitialModel(db *sql.DB, jiraClient *jira.Client, jql string, jiraTimeDeltaMins int) model {
Expand All @@ -15,19 +15,34 @@ func InitialModel(db *sql.DB, jiraClient *jira.Client, jql string, jiraTimeDelta
var appDelegateKeys = newDelegateKeyMap()
itemDel := newItemDelegate(appDelegateKeys)

ta := textarea.New()
ta.MaxHeight = 10
ta.Focus()
trackingInputs := make([]textinput.Model, 3)
trackingInputs[entryBeginTS] = textinput.New()
trackingInputs[entryBeginTS].Placeholder = "09:30"
trackingInputs[entryBeginTS].Focus()
trackingInputs[entryBeginTS].CharLimit = len(string(timeFormat))
trackingInputs[entryBeginTS].Width = 30

trackingInputs[entryEndTS] = textinput.New()
trackingInputs[entryEndTS].Placeholder = "12:30pm"
trackingInputs[entryEndTS].Focus()
trackingInputs[entryEndTS].CharLimit = len(string(timeFormat))
trackingInputs[entryEndTS].Width = 30

trackingInputs[entryComment] = textinput.New()
trackingInputs[entryComment].Placeholder = "Your comment goes here"
trackingInputs[entryComment].Focus()
trackingInputs[entryComment].CharLimit = 255
trackingInputs[entryComment].Width = 60

m := model{
db: db,
jiraClient: jiraClient,
jql: jql,
issueList: list.New(stackItems, itemDel, listWidth, 0),
worklogList: list.New(worklogListItems, itemDel, listWidth, 0),
commentInput: ta,
jiraTimeDeltaMins: jiraTimeDeltaMins,
showHelpIndicator: true,
trackingInputs: trackingInputs,
}
m.issueList.Title = "Issues (fetching ...)"
m.issueList.SetStatusBarItemName("issue", "issues")
Expand Down
58 changes: 36 additions & 22 deletions ui/model.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import (

jira "github.com/andygrunwald/go-jira/v2/onpremise"
"github.com/charmbracelet/bubbles/list"
"github.com/charmbracelet/bubbles/textarea"
"github.com/charmbracelet/bubbles/textinput"
"github.com/charmbracelet/bubbles/viewport"
tea "github.com/charmbracelet/bubbletea"
)
Expand All @@ -33,31 +33,45 @@ const (
IssueListView StateView = iota
WorklogView
AskForCommentView
EntryTrackingView
HelpView
)

type trackingFocussedField uint

const (
entryBeginTS trackingFocussedField = iota
entryEndTS
entryComment
)

const (
timeFormat = "2006/01/02 15:04"
)

type model struct {
activeView StateView
lastView StateView
db *sql.DB
jiraClient *jira.Client
jql string
issueList list.Model
worklogList list.Model
helpVP viewport.Model
helpVPReady bool
commentInput textarea.Model
lastChange DBChange
changesLocked bool
activeIssue string
activeIssueIndex int
issueDetails map[string]string
message string
errorMessage string
messages []string
jiraTimeDeltaMins int
showHelpIndicator bool
terminalHeight int
activeView StateView
lastView StateView
db *sql.DB
jiraClient *jira.Client
jql string
issueList list.Model
worklogList list.Model
trackingInputs []textinput.Model
trackingFocussedField trackingFocussedField
helpVP viewport.Model
helpVPReady bool
lastChange DBChange
changesLocked bool
activeIssue string
activeIssueIndex int
issueDetails map[string]string
message string
errorMessage string
messages []string
jiraTimeDeltaMins int
showHelpIndicator bool
terminalHeight int
}

func (m model) Init() tea.Cmd {
Expand Down
5 changes: 5 additions & 0 deletions ui/msgs.go
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,11 @@ type InsertEntryMsg struct {
err error
}

type ManualEntryInserted struct {
issueKey string
err error
}

type UpdateEntryMsg struct {
issueKey string
err error
Expand Down
6 changes: 6 additions & 0 deletions ui/styles.go
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,12 @@ var (
notSyncedStyle = statusStyle.Copy().
Background(lipgloss.Color("#fb4934"))

formContextStyle = lipgloss.NewStyle().
Foreground(lipgloss.Color("#fe8019"))

formFieldNameStyle = lipgloss.NewStyle().
Foreground(lipgloss.Color("#504945"))

activeIssueMsgStyle = baseStyle.Copy().
Bold(true).
Foreground(lipgloss.Color("#d3869b"))
Expand Down
141 changes: 130 additions & 11 deletions ui/update.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
package ui

import (
"log"
"time"

"github.com/charmbracelet/bubbles/list"
"github.com/charmbracelet/bubbles/viewport"
tea "github.com/charmbracelet/bubbletea"
Expand All @@ -18,27 +21,106 @@ func (m model) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
case tea.KeyMsg:
switch msg.String() {
case "ctrl+d":
if m.activeView == AskForCommentView {
switch m.activeView {
case AskForCommentView:
m.activeView = IssueListView
if m.commentInput.Value() != "" {
cmds = append(cmds, toggleTracking(m.db, m.activeIssue, m.commentInput.Value()))
m.commentInput.SetValue("")
if m.trackingInputs[entryComment].Value() != "" {
cmds = append(cmds, toggleTracking(m.db, m.activeIssue, m.trackingInputs[entryComment].Value()))
m.trackingInputs[entryComment].SetValue("")
return m, tea.Batch(cmds...)
}
case EntryTrackingView:
m.activeView = IssueListView

issue, ok := m.issueList.SelectedItem().(Issue)
beginTS, err := time.ParseInLocation(string(timeFormat), m.trackingInputs[entryBeginTS].Value(), time.Local)
if err != nil {
m.errorMessage = err.Error()
log.Println(err.Error())
return m, tea.Batch(cmds...)
}

endTS, err := time.ParseInLocation(string(timeFormat), m.trackingInputs[entryEndTS].Value(), time.Local)

if err != nil {
m.errorMessage = err.Error()
return m, tea.Batch(cmds...)
}

comment := m.trackingInputs[entryComment].Value()

if len(comment) == 0 {
m.errorMessage = "Comment cannot be empty"
return m, tea.Batch(cmds...)

}

if ok {
cmds = append(cmds, insertManualEntry(m.db, issue.IssueKey, beginTS.Local(), endTS.Local(), comment))
}

for i := range m.trackingInputs {
m.trackingInputs[i].SetValue("")
}
return m, tea.Batch(cmds...)
}
case "esc":
if m.activeView == AskForCommentView {
switch m.activeView {
case AskForCommentView:
m.activeView = IssueListView
m.commentInput.SetValue("")
m.trackingInputs[entryComment].SetValue("")
case EntryTrackingView:
m.activeView = IssueListView
for i := range m.trackingInputs {
m.trackingInputs[i].SetValue("")
}
}
case "tab":
switch m.activeView {
case EntryTrackingView:
switch m.trackingFocussedField {
case entryBeginTS:
m.trackingFocussedField = entryEndTS
case entryEndTS:
m.trackingFocussedField = entryComment
case entryComment:
m.trackingFocussedField = entryBeginTS
}
for i := range m.trackingInputs {
m.trackingInputs[i].Blur()
}
m.trackingInputs[m.trackingFocussedField].Focus()
}
case "shift+tab":
switch m.activeView {
case EntryTrackingView:
switch m.trackingFocussedField {
case entryBeginTS:
m.trackingFocussedField = entryComment
case entryEndTS:
m.trackingFocussedField = entryBeginTS
case entryComment:
m.trackingFocussedField = entryEndTS
}
for i := range m.trackingInputs {
m.trackingInputs[i].Blur()
}
m.trackingInputs[m.trackingFocussedField].Focus()
}
}
}

switch m.activeView {
case AskForCommentView:
m.commentInput, cmd = m.commentInput.Update(msg)
m.trackingInputs[entryComment], cmd = m.trackingInputs[entryComment].Update(msg)
cmds = append(cmds, cmd)
return m, tea.Batch(cmds...)
case EntryTrackingView:
for i := range m.trackingInputs {
m.trackingInputs[i], cmd = m.trackingInputs[i].Update(msg)
cmds = append(cmds, cmd)
}
return m, tea.Batch(cmds...)
}

switch msg := msg.(type) {
Expand Down Expand Up @@ -79,6 +161,23 @@ func (m model) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
cmds = append(cmds, fetchLogEntries(m.db))
return m, tea.Batch(cmds...)
}
case "ctrl+s":
if m.activeView == IssueListView {
m.activeView = EntryTrackingView
m.trackingFocussedField = entryBeginTS
currentTime := time.Now()
dateString := currentTime.Format("2006/01/02")
currentTimeStr := currentTime.Format(timeFormat)

m.trackingInputs[entryBeginTS].SetValue(dateString + " ")
m.trackingInputs[entryEndTS].SetValue(currentTimeStr)

for i := range m.trackingInputs {
m.trackingInputs[i].Blur()
}
m.trackingInputs[m.trackingFocussedField].Focus()
return m, tea.Batch(cmds...)
}
case "ctrl+d":
switch m.activeView {
case WorklogView:
Expand Down Expand Up @@ -113,6 +212,8 @@ func (m model) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
cmds = append(cmds, toggleTracking(m.db, issue.IssueKey, ""))
} else if m.lastChange == InsertChange {
m.activeView = AskForCommentView
m.trackingFocussedField = entryComment
m.trackingInputs[m.trackingFocussedField].Focus()
}
}
}
Expand All @@ -135,15 +236,19 @@ func (m model) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
}

case tea.WindowSizeMsg:
_, h1 := stackListStyle.GetFrameSize()
w, h := stackListStyle.GetFrameSize()
m.terminalHeight = msg.Height
m.issueList.SetHeight(msg.Height - h1 - 2)
m.worklogList.SetHeight(msg.Height - h1 - 2)
m.issueList.SetHeight(msg.Height - h - 2)
m.worklogList.SetHeight(msg.Height - h - 2)
if !m.helpVPReady {
m.helpVP = viewport.New(120, m.terminalHeight-7)
m.helpVP = viewport.New(w-5, m.terminalHeight-7)
m.helpVP.HighPerformanceRendering = useHighPerformanceRenderer
m.helpVP.SetContent(HelpText)
m.helpVPReady = true
} else {
m.helpVP.Height = m.terminalHeight - 7
m.helpVP.Width = w - 5

}
case IssuesFetchedFromJIRAMsg:
if msg.err != nil {
Expand All @@ -166,6 +271,17 @@ func (m model) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
} else {
m.activeIssue = msg.issueKey
}
case ManualEntryInserted:
if msg.err != nil {
message := msg.err.Error()
m.message = message
m.messages = append(m.messages, message)
} else {
m.message = "Manual entry saved"
for i := range m.trackingInputs {
m.trackingInputs[i].SetValue("")
}
}
case LogEntriesFetchedMsg:
if msg.err != nil {
message := msg.err.Error()
Expand Down Expand Up @@ -251,6 +367,9 @@ func (m model) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
case WorklogView:
m.worklogList, cmd = m.worklogList.Update(msg)
cmds = append(cmds, cmd)
case HelpView:
m.helpVP, cmd = m.helpVP.Update(msg)
cmds = append(cmds, cmd)
}

return m, tea.Batch(cmds...)
Expand Down
Loading

0 comments on commit af39d15

Please sign in to comment.